Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

FFmpeg "movflags" > "faststart" causes invalid MP4 file to be written

I'm setting up the format layout for the video as follows:

AVOutputFormat* outputFormat = ffmpeg.av_guess_format(null, "output.mp4", null);

AVCodec* videoCodec = ffmpeg.avcodec_find_encoder(outputFormat->video_codec);

AVFormatContext* formatContext = ffmpeg.avformat_alloc_context();
formatContext->oformat = outputFormat;
formatContext->video_codec_id = videoCodec->id;

ffmpeg.avformat_new_stream(formatContext, videoCodec);

This is how I am setting up the Codec Context:

AVCodecContext* codecContext = ffmpeg.avcodec_alloc_context3(videoCodec);
codecContext->bit_rate = 400000;
codecContext->width = 1280;
codecContext->height = 720;
codecContext->gop_size = 12;
codecContext->max_b_frames = 1;
codecContext->pix_fmt = videoCodec->pix_fmts[0];
codecContext->codec_id = videoCodec->id;
codecContext->codec_type = videoCodec->type;
codecContext->time_base = new AVRational
{
    num = 1,
    den = 30
};

I'm using the following code to setup the "movflags" > "faststart" option for the header of the video:

AVDictionary* options = null;

int result = ffmpeg.av_dict_set(&options, "movflags", "faststart", 0);

int writeHeaderResult = ffmpeg.avformat_write_header(formatContext, &options);

The file is opened and the header is written as follows:

if ((formatContext->oformat->flags & ffmpeg.AVFMT_NOFILE) == 0)
{
    int ioOptionResult = ffmpeg.avio_open(&formatContext->pb, "output.mp4", ffmpeg.AVIO_FLAG_WRITE);
}

int writeHeaderResult = ffmpeg.avformat_write_header(formatContext, &options);

After this, I write each video frame as follows:

outputFrame->pts = frameIndex;

packet.flags |= ffmpeg.AV_PKT_FLAG_KEY;
packet.pts = frameIndex;
packet.dts = frameIndex;

int encodedFrame = 0;
int encodeVideoResult = ffmpeg.avcodec_encode_video2(codecContext, &packet, outputFrame, &encodedFrame);

if (encodedFrame != 0)
{
    packet.pts = ffmpeg.av_rescale_q(packet.pts, codecContext->time_base, m_videoStream->time_base);
    packet.dts = ffmpeg.av_rescale_q(packet.dts, codecContext->time_base, m_videoStream->time_base);
    packet.stream_index = m_videoStream->index;

    if (codecContext->coded_frame->key_frame > 0)
    {
        packet.flags |= ffmpeg.AV_PKT_FLAG_KEY;
    }

    int writeFrameResult = ffmpeg.av_interleaved_write_frame(formatContext, &packet);
}

After that, I write the trailer:

int writeTrailerResult = ffmpeg.av_write_trailer(formatContext);

The file finishes writing and everything closes and frees up correctly. However, the MP4 file is unplayable (even VLC cant play it). AtomicParsley.exe won't show any information about the file either.

The DLLs used for the AutoGen library are:

avcodec-56.dll
avdevice-56.dll
avfilter-5.dll
avformat-56.dll
avutil-54.dll
postproc-53.dll
swresample-1.dll
swscale-3.dll
like image 792
williamtroup Avatar asked Nov 08 '22 12:11

williamtroup


1 Answers

It would appear using "faststart" on its own causes the problem. As long as you setup your segment sizes correctly via the "movflags" ("frag_duration" in my case), it should be fine.

Also, it would be better to ensure that both streams in the video are correctly synced. See this question for answers in regards to this.

like image 89
williamtroup Avatar answered Nov 14 '22 23:11

williamtroup