Recherche avancée

Médias (91)

Autres articles (74)

  • Des sites réalisés avec MediaSPIP

    2 mai 2011, par

    Cette page présente quelques-uns des sites fonctionnant sous MediaSPIP.
    Vous pouvez bien entendu ajouter le votre grâce au formulaire en bas de page.

  • Participer à sa traduction

    10 avril 2011

    Vous pouvez nous aider à améliorer les locutions utilisées dans le logiciel ou à traduire celui-ci dans n’importe qu’elle nouvelle langue permettant sa diffusion à de nouvelles communautés linguistiques.
    Pour ce faire, on utilise l’interface de traduction de SPIP où l’ensemble des modules de langue de MediaSPIP sont à disposition. ll vous suffit de vous inscrire sur la liste de discussion des traducteurs pour demander plus d’informations.
    Actuellement MediaSPIP n’est disponible qu’en français et (...)

  • Le profil des utilisateurs

    12 avril 2011, par

    Chaque utilisateur dispose d’une page de profil lui permettant de modifier ses informations personnelle. Dans le menu de haut de page par défaut, un élément de menu est automatiquement créé à l’initialisation de MediaSPIP, visible uniquement si le visiteur est identifié sur le site.
    L’utilisateur a accès à la modification de profil depuis sa page auteur, un lien dans la navigation "Modifier votre profil" est (...)

Sur d’autres sites (8111)

  • FFmpeg how to apply "aac_adtstoasc" and "h264_mp4toannexb" bitstream filters to transcode to h.264 with AAC

    9 juillet 2015, par larod

    I’ve been struggling with this issue for about a month, I have studied FFmpeg documentation more specifically transcode_aac.c, transcoding.c, decoding_encoding.c and Handbrake’s implementation which is really dense.

    The error that I’m getting is the following : [mp4 @ 0x11102f800] Malformed AAC bitstream detected: use the audio bitstream filter 'aac_adtstoasc' to fix it ('-bsf:a aac_adtstoasc' option with ffmpeg).

    The research I’ve done points to a filter that needs to be implemented.

    FIX:AAC in some container format (FLV, MP4, MKV etc.) need "aac_adtstoasc" bitstream filter (BSF).

    I know I can do the following :

    AVBitStreamFilterContext* aacbsfc =  av_bitstream_filter_init("aac_adtstoasc");

    And then do something like this :

    av_bitstream_filter_filter(aacbsfc, in_stream->codec, NULL, &pkt.data, &pkt.size, pkt.data, pkt.size, 0);

    What eludes me is when to filter the AVPacket, is it before calling av_packet_rescale_ts or inside init_filter. I would greatly appreciate if someone can point me in the right direction. Thanks in advance.

    // Variables
    AVFormatContext *_ifmt_ctx, *_ofmt_ctx;
    FilteringContext *_filter_ctx;
    AVBitStreamFilterContext *_h264bsfc;
    AVBitStreamFilterContext *_aacbsfc;
    NSURL *_srcURL, *_dstURL;

    - (IBAction)trancode:(id)sender {
           NSLog(@"%s %@",__func__, _mediaFile.fsName);
           int ret, got_frame;
           int (*dec_func)(AVCodecContext *, AVFrame *, int *, const AVPacket *);
           unsigned int stream_index, i;
           enum AVMediaType type;
           AVPacket packet = {.data = NULL, .size = 0};
           AVFrame *frame = NULL;
           _h264bsfc = av_bitstream_filter_init("h264_mp4toannexb");
           _aacbsfc =  av_bitstream_filter_init("aac_adtstoasc");

       _srcURL = [Utility urlFromBookmark:_mediaFile.bookmark];
       if ([_srcURL startAccessingSecurityScopedResource]) {
           NSString *newFileName = [[_srcURL.lastPathComponent stringByDeletingPathExtension]stringByAppendingPathExtension:@"mp4"];
           _dstURL = [NSURL fileURLWithPath:[[_srcURL URLByDeletingLastPathComponent]URLByAppendingPathComponent:newFileName].path isDirectory:NO];

           [AppDelegate ffmpegRegisterAll];

           ret = open_input_file(_srcURL.path.fileSystemRepresentation);
           if (ret < 0) {
               NSLog(@"Error openning input file.");
           }

           ret = open_output_file(_dstURL.path.fileSystemRepresentation);
           if (ret < 0) {
               NSLog(@"Error openning output file.");
           }

           ret = init_filters();
           if (ret < 0) {
               NSLog(@"Error initializing filters.");
           }

           AVBitStreamFilterContext *h264bsfc = av_bitstream_filter_init("h264_mp4toannexb");
           AVBitStreamFilterContext* aacbsfc =  av_bitstream_filter_init("aac_adtstoasc");
           // Transcode *******************************************************************************
           while (1) {
               if ((ret = av_read_frame(_ifmt_ctx, &packet)) < 0) {
                   break;
               }
               stream_index = packet.stream_index;
               type = _ifmt_ctx->streams[packet.stream_index]->codec->codec_type;
               av_log(NULL, AV_LOG_DEBUG, "Demuxer gave frame of stream_index %u\n", stream_index);



               if (_filter_ctx[stream_index].filter_graph) {
                   av_log(NULL, AV_LOG_DEBUG, "Going to reencode&filter the frame\n");
                   frame = av_frame_alloc();
                   if (!frame) {
                       ret = AVERROR(ENOMEM);
                       break;
                   }

                   av_packet_rescale_ts(&packet, _ifmt_ctx->streams[stream_index]->time_base, _ifmt_ctx->streams[stream_index]->codec->time_base);
                   dec_func = (type == AVMEDIA_TYPE_VIDEO) ? avcodec_decode_video2 : avcodec_decode_audio4;
                   ret = dec_func(_ifmt_ctx->streams[stream_index]->codec, frame, &got_frame, &packet);
                   if (ret < 0) {
                       av_frame_free(&frame);
                       av_log(NULL, AV_LOG_ERROR, "Decoding failed\n");
                       break;
                   }

                   if (got_frame) {
                       frame->pts = av_frame_get_best_effort_timestamp(frame);
                       ret = filter_encode_write_frame(frame, stream_index);
                       av_frame_free(&frame);
                       if (ret < 0)
                           goto end;
                   } else {
                       av_frame_free(&frame);
                   }
               } else {
                   /* remux this frame without reencoding */
                   av_packet_rescale_ts(&packet,
                                        _ifmt_ctx->streams[stream_index]->time_base,
                                        _ofmt_ctx->streams[stream_index]->time_base);

                   ret = av_interleaved_write_frame(_ofmt_ctx, &packet);
                   if (ret < 0)
                       goto end;
               }
               av_free_packet(&packet);
           }
           // *****************************************************************************************

           /* flush filters and encoders */
           for (i = 0; i < _ifmt_ctx->nb_streams; i++) {
               /* flush filter */
               if (!_filter_ctx[i].filter_graph)
                   continue;
               ret = filter_encode_write_frame(NULL, i);
               if (ret < 0) {
                   av_log(NULL, AV_LOG_ERROR, "Flushing filter failed\n");
                   goto end;
               }

               /* flush encoder */
               ret = flush_encoder(i);
               if (ret < 0) {
                   av_log(NULL, AV_LOG_ERROR, "Flushing encoder failed\n");
                   goto end;
               }
           }
           av_write_trailer(_ofmt_ctx);
           av_bitstream_filter_close(h264bsfc);
           av_bitstream_filter_close(aacbsfc);
       } else {
           NSLog(@"Unable to resolve url for %@",_mediaFile.url.lastPathComponent);
       }
       [_srcURL stopAccessingSecurityScopedResource];

    end:
       av_free_packet(&packet);
       av_frame_free(&frame);
       for (i = 0; i < _ifmt_ctx->nb_streams; i++) {
           avcodec_close(_ifmt_ctx->streams[i]->codec);
           if (_ofmt_ctx && _ofmt_ctx->nb_streams > i && _ofmt_ctx->streams[i] && _ofmt_ctx->streams[i]->codec)
               avcodec_close(_ofmt_ctx->streams[i]->codec);
           if (_filter_ctx && _filter_ctx[i].filter_graph)
               avfilter_graph_free(&_filter_ctx[i].filter_graph);
       }
       av_free(_filter_ctx);
       avformat_close_input(&_ifmt_ctx);
       if (_ofmt_ctx && !(_ofmt_ctx->oformat->flags & AVFMT_NOFILE))
           avio_closep(&_ofmt_ctx->pb);
       avformat_free_context(_ofmt_ctx);
    }

    The following method is used to open the input file and create the ifmt_ctx.

    int open_input_file(const char *filename) {
       int ret;
       unsigned int i;

       _ifmt_ctx = NULL;
       if ((ret = avformat_open_input(&_ifmt_ctx, filename, NULL, NULL)) < 0) {
           av_log(NULL, AV_LOG_ERROR, "Cannot open input file\n");
           return ret;
       }

       if ((ret = avformat_find_stream_info(_ifmt_ctx, NULL)) < 0) {
           av_log(NULL, AV_LOG_ERROR, "Cannot find stream information\n");
           return ret;
       }

       for (i = 0; i < _ifmt_ctx->nb_streams; i++) {
           AVStream *stream;
           AVCodecContext *codec_ctx;
           stream = _ifmt_ctx->streams[i];
           codec_ctx = stream->codec;
           /* Reencode video & audio and remux subtitles etc. */
           if (codec_ctx->codec_type == AVMEDIA_TYPE_VIDEO
               || codec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) {
               /* Open decoder */
               ret = avcodec_open2(codec_ctx,
                                   avcodec_find_decoder(codec_ctx->codec_id), NULL);
               if (ret < 0) {
                   av_log(NULL, AV_LOG_ERROR, "Failed to open decoder for stream #%u\n", i);
                   return ret;
               }
           }
       }

       // Remove later
       av_dump_format(_ifmt_ctx, 0, filename, 0);
       return 0;
    }

    This method is used to open the output file and create the output format context.

    int open_output_file(const char *filename) {
       AVStream *out_stream;
       AVStream *in_stream;
       AVCodecContext *dec_ctx, *enc_ctx;
       AVCodec *encoder;
       int ret;
       unsigned int i;

       _ofmt_ctx = NULL;
       avformat_alloc_output_context2(&_ofmt_ctx, NULL, NULL, filename);
       if (!_ofmt_ctx) {
           av_log(NULL, AV_LOG_ERROR, "Could not create output context\n");
           return AVERROR_UNKNOWN;
       }


       for (i = 0; i < _ifmt_ctx->nb_streams; i++) {
           out_stream = avformat_new_stream(_ofmt_ctx, NULL);
           if (!out_stream) {
               av_log(NULL, AV_LOG_ERROR, "Failed allocating output stream\n");
               return AVERROR_UNKNOWN;
           }

           in_stream = _ifmt_ctx->streams[i];
           dec_ctx = in_stream->codec;
           enc_ctx = out_stream->codec;

           if (dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO) {
               // set video stream
               encoder = avcodec_find_encoder(AV_CODEC_ID_H264);
               avcodec_get_context_defaults3(enc_ctx, encoder);
               av_opt_set(enc_ctx->priv_data, "preset", "slow", 0);
               enc_ctx->height = dec_ctx->height;
               enc_ctx->width = dec_ctx->width;
               enc_ctx->bit_rate = dec_ctx->bit_rate;
               enc_ctx->time_base = out_stream->time_base = dec_ctx->time_base;
               enc_ctx->pix_fmt = encoder->pix_fmts[0];

               ret = avcodec_open2(enc_ctx, encoder, NULL);
               if (ret < 0) {
                   av_log(NULL, AV_LOG_ERROR, "Cannot open video encoder for stream #%u\n", i);
                   return ret;
               }

           } else if (dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) {
               // set audio stream
               //encoder = avcodec_find_encoder(AV_CODEC_ID_AAC);
               encoder = avcodec_find_encoder_by_name("libfdk_aac");
               avcodec_get_context_defaults3(enc_ctx, encoder);
               enc_ctx->profile = FF_PROFILE_AAC_HE_V2;
               enc_ctx->sample_rate = dec_ctx->sample_rate;
               enc_ctx->channel_layout = dec_ctx->channel_layout;
               enc_ctx->channels = av_get_channel_layout_nb_channels(enc_ctx->channel_layout);
               enc_ctx->sample_fmt = encoder->sample_fmts[0];
               enc_ctx->time_base = out_stream->time_base = (AVRational){1, enc_ctx->sample_rate};
               enc_ctx->bit_rate = dec_ctx->bit_rate;

               ret = avcodec_open2(enc_ctx, encoder, NULL);
               if (ret < 0) {
                   av_log(NULL, AV_LOG_ERROR, "Cannot open video encoder for stream #%u\n", i);
                   return ret;
               }

           } else if (dec_ctx->codec_type == AVMEDIA_TYPE_UNKNOWN) {
               // deal with error
               av_log(NULL, AV_LOG_FATAL, "Elementary stream #%d is of unknown type, cannot proceed\n", i);
               return AVERROR_INVALIDDATA;
           } else {
               // remux stream
               ret = avcodec_copy_context(_ofmt_ctx->streams[i]->codec,
                                          _ifmt_ctx->streams[i]->codec);
               if (ret < 0) {
                   av_log(NULL, AV_LOG_ERROR, "Copying stream context failed\n");
                   return ret;
               }
           }

           if (_ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER) {
               enc_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER;
           }
       }

       av_dump_format(_ofmt_ctx, 0, filename, 1);

       NSURL *openFileURL = [Utility openPanelAt:[NSURL URLWithString:_dstURL.URLByDeletingLastPathComponent.path]
                                       withTitle:@"Transcode File"
                                         message:@"Please allow Maví to create the new file."
                                       andPrompt:@"Grant Access"];

       openFileURL = [openFileURL URLByAppendingPathComponent:_dstURL.lastPathComponent isDirectory:NO];
       if (!(_ofmt_ctx->oformat->flags & AVFMT_NOFILE)) {
           ret = avio_open(&_ofmt_ctx->pb, openFileURL.fileSystemRepresentation, AVIO_FLAG_WRITE);
           if (ret < 0) {
               av_log(NULL, AV_LOG_ERROR, "Could not open output file '%s'", filename);
               return ret;
           }
       }

       /* init muxer, write output file header */
       ret = avformat_write_header(_ofmt_ctx, NULL);
       if (ret < 0) {
           av_log(NULL, AV_LOG_ERROR, "Error occurred when opening output file\n");
           return ret;
       }

       return 0;
    }

    These two methods deal with initialising the filters and filtering.

    int init_filters(void) {
       const char *filter_spec;
       unsigned int i;
       int ret;
       _filter_ctx = av_malloc_array(_ifmt_ctx->nb_streams, sizeof(*_filter_ctx));
       if (!_filter_ctx)
           return AVERROR(ENOMEM);

       for (i = 0; i < _ifmt_ctx->nb_streams; i++) {
           _filter_ctx[i].buffersrc_ctx  = NULL;
           _filter_ctx[i].buffersink_ctx = NULL;
           _filter_ctx[i].filter_graph   = NULL;
           if (!(_ifmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO
                 || _ifmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO))
               continue;


           if (_ifmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
               filter_spec = "null"; /* passthrough (dummy) filter for video */
           else
               filter_spec = "anull"; /* passthrough (dummy) filter for audio */
           ret = init_filter(&_filter_ctx[i], _ifmt_ctx->streams[i]->codec,
                             _ofmt_ctx->streams[i]->codec, filter_spec);
           if (ret)
               return ret;
       }
       return 0;
    }
    int init_filter(FilteringContext* fctx, AVCodecContext *dec_ctx, AVCodecContext *enc_ctx, const char *filter_spec) {
       char args[512];
       int ret = 0;
       AVFilter *buffersrc = NULL;
       AVFilter *buffersink = NULL;
       AVFilterContext *buffersrc_ctx = NULL;
       AVFilterContext *buffersink_ctx = NULL;
       AVFilterInOut *outputs = avfilter_inout_alloc();
       AVFilterInOut *inputs  = avfilter_inout_alloc();
       AVFilterGraph *filter_graph = avfilter_graph_alloc();

       if (!outputs || !inputs || !filter_graph) {
           ret = AVERROR(ENOMEM);
           goto end;
       }

       if (dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO) {
           buffersrc = avfilter_get_by_name("buffer");
           buffersink = avfilter_get_by_name("buffersink");
           if (!buffersrc || !buffersink) {
               av_log(NULL, AV_LOG_ERROR, "filtering source or sink element not found\n");
               ret = AVERROR_UNKNOWN;
               goto end;
           }

           snprintf(args, sizeof(args),
                    "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
                    dec_ctx->width, dec_ctx->height, dec_ctx->pix_fmt,
                    dec_ctx->time_base.num, dec_ctx->time_base.den,
                    dec_ctx->sample_aspect_ratio.num,
                    dec_ctx->sample_aspect_ratio.den);

           ret = avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in",
                                              args, NULL, filter_graph);
           if (ret < 0) {
               av_log(NULL, AV_LOG_ERROR, "Cannot create buffer source\n");
               goto end;
           }

           ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out",
                                              NULL, NULL, filter_graph);
           if (ret < 0) {
               av_log(NULL, AV_LOG_ERROR, "Cannot create buffer sink\n");
               goto end;
           }

           ret = av_opt_set_bin(buffersink_ctx, "pix_fmts",
                                (uint8_t*)&enc_ctx->pix_fmt, sizeof(enc_ctx->pix_fmt),
                                AV_OPT_SEARCH_CHILDREN);
           if (ret < 0) {
               av_log(NULL, AV_LOG_ERROR, "Cannot set output pixel format\n");
               goto end;
           }
       } else if (dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) {
           buffersrc = avfilter_get_by_name("abuffer");
           buffersink = avfilter_get_by_name("abuffersink");
           if (!buffersrc || !buffersink) {
               av_log(NULL, AV_LOG_ERROR, "filtering source or sink element not found\n");
               ret = AVERROR_UNKNOWN;
               goto end;
           }

           if (!dec_ctx->channel_layout)
               dec_ctx->channel_layout =
               av_get_default_channel_layout(dec_ctx->channels);
           snprintf(args, sizeof(args),
                    "time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=0x%"PRIx64,
                    dec_ctx->time_base.num, dec_ctx->time_base.den, dec_ctx->sample_rate,
                    av_get_sample_fmt_name(dec_ctx->sample_fmt),
                    dec_ctx->channel_layout);
           ret = avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in",
                                              args, NULL, filter_graph);
           if (ret < 0) {
               av_log(NULL, AV_LOG_ERROR, "Cannot create audio buffer source\n");
               goto end;
           }

           ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out",
                                              NULL, NULL, filter_graph);
           if (ret < 0) {
               av_log(NULL, AV_LOG_ERROR, "Cannot create audio buffer sink\n");
               goto end;
           }

           ret = av_opt_set_bin(buffersink_ctx, "sample_fmts",
                                (uint8_t*)&enc_ctx->sample_fmt, sizeof(enc_ctx->sample_fmt),
                                AV_OPT_SEARCH_CHILDREN);
           if (ret < 0) {
               av_log(NULL, AV_LOG_ERROR, "Cannot set output sample format\n");
               goto end;
           }

           ret = av_opt_set_bin(buffersink_ctx, "channel_layouts",
                                (uint8_t*)&enc_ctx->channel_layout,
                                sizeof(enc_ctx->channel_layout), AV_OPT_SEARCH_CHILDREN);
           if (ret < 0) {
               av_log(NULL, AV_LOG_ERROR, "Cannot set output channel layout\n");
               goto end;
           }

           ret = av_opt_set_bin(buffersink_ctx, "sample_rates",
                                (uint8_t*)&enc_ctx->sample_rate, sizeof(enc_ctx->sample_rate),
                                AV_OPT_SEARCH_CHILDREN);
           if (ret < 0) {
               av_log(NULL, AV_LOG_ERROR, "Cannot set output sample rate\n");
               goto end;
           }
       } else {
           ret = AVERROR_UNKNOWN;
           goto end;
       }

       /* Endpoints for the filter graph. */
       outputs->name       = av_strdup("in");
       outputs->filter_ctx = buffersrc_ctx;
       outputs->pad_idx    = 0;
       outputs->next       = NULL;

       inputs->name       = av_strdup("out");
       inputs->filter_ctx = buffersink_ctx;
       inputs->pad_idx    = 0;
       inputs->next       = NULL;

       if (!outputs->name || !inputs->name) {
           ret = AVERROR(ENOMEM);
           goto end;
       }

       if ((ret = avfilter_graph_parse_ptr(filter_graph, filter_spec,
                                           &inputs, &outputs, NULL)) < 0)
           goto end;

       if ((ret = avfilter_graph_config(filter_graph, NULL)) < 0)
           goto end;

       /* Fill FilteringContext */
       fctx->buffersrc_ctx = buffersrc_ctx;
       fctx->buffersink_ctx = buffersink_ctx;
       fctx->filter_graph = filter_graph;

    end:
       avfilter_inout_free(&inputs);
       avfilter_inout_free(&outputs);

       return ret;
    }

    Finally these two methods take care of writing the frames.

    int encode_write_frame(AVFrame *filt_frame, unsigned int stream_index, int *got_frame) {
       int ret;
       int got_frame_local;
       AVPacket enc_pkt;
       int (*enc_func)(AVCodecContext *, AVPacket *, const AVFrame *, int *) =
       (_ifmt_ctx->streams[stream_index]->codec->codec_type ==
        AVMEDIA_TYPE_VIDEO) ? avcodec_encode_video2 : avcodec_encode_audio2;

       if (!got_frame)
           got_frame = &got_frame_local;

       av_log(NULL, AV_LOG_INFO, "Encoding frame\n");
       /* encode filtered frame */
       enc_pkt.data = NULL;
       enc_pkt.size = 0;
       av_init_packet(&enc_pkt);
       ret = enc_func(_ofmt_ctx->streams[stream_index]->codec, &enc_pkt,
                      filt_frame, got_frame);
       av_frame_free(&filt_frame);
       if (ret < 0)
           return ret;
       if (!(*got_frame))
           return 0;

       /* prepare packet for muxing */
       enc_pkt.stream_index = stream_index;
       av_packet_rescale_ts(&enc_pkt,
                            _ofmt_ctx->streams[stream_index]->codec->time_base,
                            _ofmt_ctx->streams[stream_index]->time_base);

       av_log(NULL, AV_LOG_DEBUG, "Muxing frame\n");
       /* mux encoded frame */
       ret = av_interleaved_write_frame(_ofmt_ctx, &enc_pkt);
       return ret;
    }
    int filter_encode_write_frame(AVFrame *frame, unsigned int stream_index)
    {
       int ret;
       AVFrame *filt_frame;

       av_log(NULL, AV_LOG_INFO, "Pushing decoded frame to filters\n");
       /* push the decoded frame into the filtergraph */
       ret = av_buffersrc_add_frame_flags(_filter_ctx[stream_index].buffersrc_ctx,
                                          frame, 0);
       if (ret < 0) {
           av_log(NULL, AV_LOG_ERROR, "Error while feeding the filtergraph\n");
           return ret;
       }

       /* pull filtered frames from the filtergraph */
       while (1) {
           filt_frame = av_frame_alloc();
           if (!filt_frame) {
               ret = AVERROR(ENOMEM);
               break;
           }
           av_log(NULL, AV_LOG_INFO, "Pulling filtered frame from filters\n");
           ret = av_buffersink_get_frame(_filter_ctx[stream_index].buffersink_ctx,
                                         filt_frame);
           if (ret < 0) {
               /* if no more frames for output - returns AVERROR(EAGAIN)
                * if flushed and no more frames for output - returns AVERROR_EOF
                * rewrite retcode to 0 to show it as normal procedure completion
                */
               if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
                   ret = 0;
               av_frame_free(&filt_frame);
               break;
           }

           filt_frame->pict_type = AV_PICTURE_TYPE_NONE;
           ret = encode_write_frame(filt_frame, stream_index, NULL);
           if (ret < 0)
               break;
       }

       return ret;
    }
  • Random segmentation fault with avcodec_encode_video2()

    10 août 2015, par Seba Arriagada

    this is my first question so i hope i did it correctly. If not, please let me know to fix it.

    I’m trying to convert a short (10 secs) mp4 video file into a gif using ffmpeg libraries (I’m pretty new using ffmpeg). The program works pretty well converting to gif, but some times it randomly crash.

    This is the version of the ffmpeg libraries I’m using :

    libavutil      54. 27.100
    libavcodec     56. 41.100
    libavformat    56. 36.100
    libavdevice    56.  4.100
    libavfilter     5. 16.101
    libavresample   2.  1.  0
    libswscale      3.  1.101
    libswresample   1.  2.100
    libpostproc    53.  3.100

    I’m using a 1920x1080p video, so in order to generate the gif I’m doing a pixel format convertion, from AV_PIX_FMT_YUV420P to AV_PIX_FMT_RGB8 with a resizing from the initial resolution to 432x240p.

    Here is the code :

    int VideoManager::loadVideo(QString filename, bool showInfo)
    {
       if(avformat_open_input(&iFmtCtx, filename.toStdString().c_str(), 0, 0) < 0)
       {
           qDebug() << "Could not open input file " << filename;
           closeInput();
           return -1;
       }
       if (avformat_find_stream_info(iFmtCtx, 0) < 0)
       {
           qDebug() << "Failed to retrieve input stream information";
           closeInput();
           return -2;
       }

       videoStreamIndex = -1;
       for(unsigned int i = 0; i < iFmtCtx->nb_streams; ++i)
           if(iFmtCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
           {
               videoStreamIndex = i;
               break;
           }

       if(videoStreamIndex == -1)
       {
           qDebug() << "Didn't find any video stream!";
           closeInput();
           return -3;
       }
       iCodecCtx = iFmtCtx->streams[videoStreamIndex]->codec;

       iCodec = avcodec_find_decoder(iCodecCtx->codec_id);
       if(iCodec == NULL) // Codec not found
       {
           qDebug() << "Codec not found!";
           closeInput();
           return -4;
       }
       if(avcodec_open2(iCodecCtx, iCodec, NULL) < 0)
       {
           qDebug() << "Could not open codec!";
           closeInput();
           return -1;
       }

       if(showInfo)
           av_dump_format(iFmtCtx, 0, filename.toStdString().c_str(), 0);

       return 0;
    }

    void VideoManager::generateGif(QString filename)
    {
       int ret, frameCount = 0;
       AVPacket packet;
       packet.data = NULL;
       packet.size = 0;
       AVFrame *frame = NULL;
       unsigned int stream_index;
       int got_frame;

       gifHeight = iFmtCtx->streams[videoStreamIndex]->codec->height;
       gifWidth  = iFmtCtx->streams[videoStreamIndex]->codec->width;

       if(gifHeight > MAX_GIF_HEIGHT || gifWidth > MAX_GIF_WIDTH)
       {
           if(gifHeight > gifWidth)
           {
               gifWidth  = (float)gifWidth * ( (float)MAX_GIF_HEIGHT / (float)gifHeight );
               gifHeight = MAX_GIF_HEIGHT;
           }
           else
           {
               gifHeight = (float)gifHeight * ( (float)MAX_GIF_WIDTH / (float)gifWidth );
               gifWidth  = MAX_GIF_WIDTH;
           }
       }


       if(openOutputFile(filename.toStdString().c_str()) < 0)
       {
           qDebug() << "Error openning output file: " << filename;
           return;
       }

       while (1) {
           int ret = av_read_frame(iFmtCtx, &packet);
           if (ret < 0)
           {
               if(ret != AVERROR_EOF)
                   qDebug() << "Error reading frame: " << ret;
               break;
           }
           stream_index = packet.stream_index;

           if(stream_index == videoStreamIndex)
           {
               frame = av_frame_alloc();
               if (!frame) {
                   qDebug() << "Error allocating frame";
                   break;
               }
               av_packet_rescale_ts(&packet,
                                    iFmtCtx->streams[stream_index]->time_base,
                                    iFmtCtx->streams[stream_index]->codec->time_base);

               ret = avcodec_decode_video2(iFmtCtx->streams[stream_index]->codec, frame,
                       &got_frame, &packet);
               if (ret < 0) {
                   qDebug() << "Decoding failed";
                   break;
               }

               if(got_frame)
               {
                   qDebug() << ++frameCount;
                   nframes++;
                   frame->pts = av_frame_get_best_effort_timestamp(frame);

                   ////////////////////////////////////////////////////////////////////////////////
                   /// Pixel format convertion and resize
                   ////////////////////////////////////////////////////////////////////////////////
                   uint8_t *out_buffer = NULL;
                   SwsContext *img_convert_ctx = NULL;
                   AVFrame *pFrameRGB = av_frame_alloc();

                   if(pFrameRGB == NULL)
                   {
                       qDebug() << "Error allocating frameRGB";
                       break;
                   }

                   AVPixelFormat pixFmt;
                   switch (iFmtCtx->streams[stream_index]->codec->pix_fmt)
                   {
                   case AV_PIX_FMT_YUVJ420P : pixFmt = AV_PIX_FMT_YUV420P; break;
                   case AV_PIX_FMT_YUVJ422P : pixFmt = AV_PIX_FMT_YUV422P; break;
                   case AV_PIX_FMT_YUVJ444P : pixFmt = AV_PIX_FMT_YUV444P; break;
                   case AV_PIX_FMT_YUVJ440P : pixFmt = AV_PIX_FMT_YUV440P; break;
                   default:
                       pixFmt = iFmtCtx->streams[stream_index]->codec->pix_fmt;
                   }

                   out_buffer = (uint8_t*)av_malloc( avpicture_get_size( AV_PIX_FMT_RGB8,
                                                     gifWidth,
                                                     gifHeight ));
                   if(!out_buffer)
                   {
                       qDebug() << "Error alocatting out_buffer!";
                   }
                   avpicture_fill((AVPicture *)pFrameRGB, out_buffer, AV_PIX_FMT_RGB8,
                                  gifWidth,
                                  gifHeight);
                   img_convert_ctx = sws_getContext( iFmtCtx->streams[stream_index]->codec->width,
                                                     iFmtCtx->streams[stream_index]->codec->height,
                                                     pixFmt,
                                                     gifWidth,
                                                     gifHeight,
                                                     AV_PIX_FMT_RGB8,
                                                     SWS_ERROR_DIFFUSION, NULL, NULL, NULL );

                   if(!img_convert_ctx)
                   {
                       qDebug() << "error getting sws context";
                   }

                   sws_scale( img_convert_ctx, (const uint8_t* const*)frame->data,
                              frame->linesize, 0,
                              iFmtCtx->streams[stream_index]->codec->height,
                              pFrameRGB->data,
                              pFrameRGB->linesize );

                   pFrameRGB->format = AV_PIX_FMT_RGB8;
                   pFrameRGB->pts = frame->pts;
                   pFrameRGB->best_effort_timestamp = frame->best_effort_timestamp;
                   pFrameRGB->width = gifWidth;
                   pFrameRGB->height = gifHeight;
                   pFrameRGB->pkt_dts = frame->pkt_dts;
                   pFrameRGB->pkt_pts = frame->pkt_pts;
                   pFrameRGB->pkt_duration = frame->pkt_duration;
                   pFrameRGB->pkt_pos = frame->pkt_pos;
                   pFrameRGB->pkt_size = frame->pkt_size;
                   pFrameRGB->interlaced_frame = frame->interlaced_frame;
                   ////////////////////////////////////////////////////////////////////////////////
                   ret = encodeAndWriteFrame(pFrameRGB, stream_index, NULL);
                   //av_frame_free(&frame);
                   //av_free(out_buffer);
                   //sws_freeContext(img_convert_ctx);
                   if (ret < 0)
                   {
                       qDebug() << "Error encoding and writting frame";
                       //av_free_packet(&packet);
                       closeOutput();
                   }
               }
               else {
                   //av_frame_free(&frame);
               }
           }
           av_free_packet(&packet);
       }

       ret = flushEncoder(videoStreamIndex);
       if (ret < 0)
       {
           qDebug() << "Flushing encoder failed";
       }

       av_write_trailer(oFmtCtx);

       //av_free_packet(&packet);
       //av_frame_free(&frame);
       closeOutput();
    }


    void VideoManager::closeOutput()
    {
       if (oFmtCtx && oFmtCtx->nb_streams > 0 && oFmtCtx->streams[0] && oFmtCtx->streams[0]->codec)
           avcodec_close(oFmtCtx->streams[0]->codec);
       if (oFmtCtx && oFmt && !(oFmt->flags & AVFMT_NOFILE))
           avio_closep(&oFmtCtx->pb);
       avformat_free_context(oFmtCtx);
    }

    int VideoManager::openOutputFile(const char *filename)
    {
       AVStream *out_stream;
       AVStream *in_stream;
       AVCodecContext *dec_ctx, *enc_ctx;
       AVCodec *encoder;
       int ret;

       oFmtCtx = NULL;
       avformat_alloc_output_context2(&oFmtCtx, NULL, NULL, filename);
       if (!oFmtCtx) {
           qDebug() << "Could not create output context";
           return AVERROR_UNKNOWN;
       }

       oFmt = oFmtCtx->oformat;

       out_stream = avformat_new_stream(oFmtCtx, NULL);
       if (!out_stream) {
           qDebug() << "Failed allocating output stream";
           return AVERROR_UNKNOWN;
       }

       in_stream = iFmtCtx->streams[videoStreamIndex];
       dec_ctx = in_stream->codec;
       enc_ctx = out_stream->codec;

       encoder = avcodec_find_encoder(AV_CODEC_ID_GIF);
       if (!encoder) {
           qDebug() << "FATAL!: Necessary encoder not found";
           return AVERROR_INVALIDDATA;
       }

       enc_ctx->height = gifHeight;    
       enc_ctx->width = gifWidth;      
       enc_ctx->sample_aspect_ratio = dec_ctx->sample_aspect_ratio;
       enc_ctx->pix_fmt = AV_PIX_FMT_RGB8;
       enc_ctx->time_base = dec_ctx->time_base;
       ret = avcodec_open2(enc_ctx, encoder, NULL);
       if (ret < 0) {
           qDebug() << "Cannot open video encoder for gif";
           return ret;
       }

       if (oFmt->flags & AVFMT_GLOBALHEADER)
           enc_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER;

       if (!(oFmt->flags & AVFMT_NOFILE)) {
           ret = avio_open(&oFmtCtx->pb, filename, AVIO_FLAG_WRITE);
           if (ret < 0) {
               qDebug() << "Could not open output file " << filename;
               return ret;
           }
       }

       ret = avformat_write_header(oFmtCtx, NULL);
       if (ret < 0) {
           qDebug() << "Error occurred when opening output file";
           return ret;
       }

       return 0;
    }


    int VideoManager::encodeAndWriteFrame(AVFrame *frame, unsigned int stream_index, int *got_frame) {
       int ret;
       int got_frame_local;
       AVPacket enc_pkt;

       if (!got_frame)
           got_frame = &got_frame_local;

       enc_pkt.data = NULL;
       enc_pkt.size = 0;
       av_init_packet(&enc_pkt);
       ret = avcodec_encode_video2(oFmtCtx->streams[stream_index]->codec, &enc_pkt,
               frame, got_frame);
       //av_frame_free(&frame);
       if (ret < 0)
           return ret;
       if (!(*got_frame))
           return 0;

       enc_pkt.stream_index = stream_index;
       av_packet_rescale_ts(&enc_pkt,
                            oFmtCtx->streams[stream_index]->codec->time_base,
                            oFmtCtx->streams[stream_index]->time_base);

       ret = av_interleaved_write_frame(oFmtCtx, &enc_pkt);
       return ret;
    }


    int VideoManager::flushEncoder(unsigned int stream_index)
    {
       int ret;
       int got_frame;

       if (!(oFmtCtx->streams[stream_index]->codec->codec->capabilities &
                   CODEC_CAP_DELAY))
           return 0;

       while (1) {
           ret = encodeAndWriteFrame(NULL, stream_index, &got_frame);
           if (ret < 0)
               break;
           if (!got_frame)
               return 0;
       }
       return ret;
    }

    I know there are a lot of memory leaks. I deleted/commented most of the free functions intentionality because i thought that was the problem.

    I’m using Qtcreator, so when i debug the programs this is the output :

    Level Function                            Line
    0     av_image_copy                       303
    1     frame_copy_video                    650    
    2     av_frame_copy                       687    
    3     av_frame_ref                        384    
    4     gif_encode_frame                    307    
    5     avcodec_encode_video2               2191    
    6     VideoManager::encodeAndWriteFrame   813    
    7     VideoManager::generateGif           375    
    8     qMain                               31    
    9     WinMain*16                          112    
    10    main

    I’ve checked if there is a specific frame the program crash at, but it’s a random frame too.

    Any idea of what i’m doing wrong ? Any help would be very appreciated.

    EDIT :

    After a few days of pain, suffering and frustation I decided to write the whole code from scratch. Both times i started from this example and modified it in order to works as I described before. And it works perfectly now :D ! The only error i could find in the old code (posted before) is when i try to access to the video stream in the output file I used videoStreamIndex, but that index is from the video stream in the input file. Some times it could be the same index and some times not. But it doesn’t explain why it crashed randomly. If that was the reason of the crash, it should crash every time i ran the code with the same video. So probably, there are more errors in that code.
    Notice that i’ve not tested if fixing that error in the code above actually solve the crashing problems.

  • movenc : Set the last packet duration based on the next packet when autoflushing

    9 mars 2015, par Martin Storsjö
    movenc : Set the last packet duration based on the next packet when autoflushing
    

    When automatically flushing fragments based on set conditions
    (fragmentation on keyframes, after some interval or byte size),
    we already have the next packet for one stream - use this for setting
    the duration of the last packet in the flushed fragment correctly.

    This avoids having to adjust the timestamp of the first packet in
    the new fragment since the last duration was unknown.

    Unfortunately, this only works for automatic flushing (not for
    caller-triggered flushing, like in the dash muxer), and only for the
    one single track that triggered the flushing. The duration of the
    last sample in all other tracks still is dependent on AVPacket
    duration (or heuristics).

    Signed-off-by : Martin Storsjö <martin@martin.st>

    • [DBH] libavformat/movenc.c