FFmpeg编码产生轻微不兼容的MKV / MP4容器

时间:2018-06-11 10:27:29

标签: encoding ffmpeg libavcodec libav libavformat

我一直在使用FFmpeg库来使用C API读取和写入媒体文件。

到目前为止,阅读似乎非常简单。我能够读取我可以处理的帧,转换为RGB,处理,然后转换回YUV420进行编码。

如果我安装了编解码器包,则编码文件可以使用VLC媒体播放器进行播放,而Windows Media Player可以播放。然而,它们确实表现得很奇怪:Windows 10播放器不会播放它们,Adobe Premiere也是如此。缩略图也不适用于它。 基本上似乎只有VLC或FFmpeg本身可以播放/处理文件。我已经看过MP4和MKV,所以它不是特定于格式的问题。

使用FFmpeg重新启动文件后,问题就会消失,例如“ffmpeg -i input.mkv -c copy output.mkv”。一切都可以正确播放文件。 此外,官方示例中的“remuxing.c”示例也可以使用,我使用的是相同的库版本和编译器(Visual Studio 2017,FFmpeg使用MinGW编译)。它将修复文件并使其在所有软件中播放。

我不确定是什么原因引起的。我也不明白什么是复兴“固定”。它必须是一个容器问题,因为remuxing不会触及框架。 我用FFprobe -show_packets分析了输出MKV。它似乎已经使数据包时间戳有点不变因素,并且输出流现在具有 is_avc = true和nal_length_size = 4而不是is_avc = false和nal_length_size = 0,但除此之外文件是相同的。

现在这里是FFprobe的输出,包含最后3个测试数据包,流信息和两个流的格式信息。正如您所看到的,除了几个字段外,它们是相同的。但是这里的某些东西必须在重新组合期间被“修复”以使其工作。

[PACKET]
codec_type=video
stream_index=0
pts=59050
pts_time=59.050000
dts=58890
dts_time=58.890000
duration=1
duration_time=0.001000
convergence_duration=N/A
convergence_duration_time=N/A
size=427
pos=277358
flags=__
[/PACKET]
[PACKET]
codec_type=video
stream_index=0
pts=58970
pts_time=58.970000
dts=58970
dts_time=58.970000
duration=1
duration_time=0.001000
convergence_duration=N/A
convergence_duration_time=N/A
size=205
pos=277792
flags=__
[/PACKET]
[PACKET]
codec_type=video
stream_index=0
pts=59130
pts_time=59.130000
dts=59050
dts_time=59.050000
duration=1
duration_time=0.001000
convergence_duration=N/A
convergence_duration_time=N/A
size=268
pos=278004
flags=__
[/PACKET]
[STREAM]
index=0
codec_name=h264
codec_long_name=H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10
profile=Main
codec_type=video
codec_time_base=1/2000
codec_tag_string=[0][0][0][0]
codec_tag=0x0000
width=720
height=576
coded_width=720
coded_height=576
has_b_frames=2
sample_aspect_ratio=N/A
display_aspect_ratio=N/A
pix_fmt=yuv420p
level=50
color_range=unknown
color_space=unknown
color_transfer=unknown
color_primaries=unknown
chroma_location=left
field_order=progressive
timecode=N/A
refs=1
is_avc=false
nal_length_size=0
id=N/A
r_frame_rate=299/12
avg_frame_rate=1000/1
time_base=1/1000
start_pts=0
start_time=0.000000
duration_ts=N/A
duration=N/A
bit_rate=N/A
max_bit_rate=N/A
bits_per_raw_sample=8
nb_frames=N/A
nb_read_frames=N/A
nb_read_packets=737
DISPOSITION:default=1
DISPOSITION:dub=0
DISPOSITION:original=0
DISPOSITION:comment=0
DISPOSITION:lyrics=0
DISPOSITION:karaoke=0
DISPOSITION:forced=0
DISPOSITION:hearing_impaired=0
DISPOSITION:visual_impaired=0
DISPOSITION:clean_effects=0
DISPOSITION:attached_pic=0
DISPOSITION:timed_thumbnails=0
TAG:DURATION=00:00:59.211000000
[/STREAM]
[FORMAT]
filename=testEncLeft.mkv
nb_streams=1
nb_programs=0
format_name=matroska,webm
format_long_name=Matroska / WebM
start_time=0.000000
duration=59.211000
size=278349
bit_rate=37607
probe_score=100
TAG:COMMENT=Slickline Player Export
TAG:ENCODER=Lavf57.83.100
[/FORMAT]

重新启动后的信息,有效:

[PACKET]
codec_type=video
stream_index=0
pts=59050
pts_time=59.050000
dts=58890
dts_time=58.890000
duration=1
duration_time=0.001000
convergence_duration=N/A
convergence_duration_time=N/A
size=427
pos=277418
flags=__
[/PACKET]
[PACKET]
codec_type=video
stream_index=0
pts=58970
pts_time=58.970000
dts=58970
dts_time=58.970000
duration=1
duration_time=0.001000
convergence_duration=N/A
convergence_duration_time=N/A
size=205
pos=277852
flags=__
[/PACKET]
[PACKET]
codec_type=video
stream_index=0
pts=59130
pts_time=59.130000
dts=59050
dts_time=59.050000
duration=1
duration_time=0.001000
convergence_duration=N/A
convergence_duration_time=N/A
size=268
pos=278064
flags=__
[/PACKET]
[STREAM]
index=0
codec_name=h264
codec_long_name=H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10
profile=Main
codec_type=video
codec_time_base=1/2000
codec_tag_string=[0][0][0][0]
codec_tag=0x0000
width=720
height=576
coded_width=720
coded_height=576
has_b_frames=2
sample_aspect_ratio=N/A
display_aspect_ratio=N/A
pix_fmt=yuv420p
level=50
color_range=unknown
color_space=unknown
color_transfer=unknown
color_primaries=unknown
chroma_location=left
field_order=progressive
timecode=N/A
refs=1
is_avc=true
nal_length_size=4
id=N/A
r_frame_rate=299/12
avg_frame_rate=1000/1
time_base=1/1000
start_pts=0
start_time=0.000000
duration_ts=N/A
duration=N/A
bit_rate=N/A
max_bit_rate=N/A
bits_per_raw_sample=8
nb_frames=N/A
nb_read_frames=N/A
nb_read_packets=737
DISPOSITION:default=1
DISPOSITION:dub=0
DISPOSITION:original=0
DISPOSITION:comment=0
DISPOSITION:lyrics=0
DISPOSITION:karaoke=0
DISPOSITION:forced=0
DISPOSITION:hearing_impaired=0
DISPOSITION:visual_impaired=0
DISPOSITION:clean_effects=0
DISPOSITION:attached_pic=0
DISPOSITION:timed_thumbnails=0
TAG:DURATION=00:00:59.212000000
[/STREAM]
[FORMAT]
filename=fixedLeft.mkv
nb_streams=1
nb_programs=0
format_name=matroska,webm
format_long_name=Matroska / WebM
start_time=0.000000
duration=59.212000
size=278409
bit_rate=37615
probe_score=100
TAG:COMMENT=Slickline Player Export
TAG:ENCODER=Lavf58.12.100
[/FORMAT]

以下是我如何设置输出上下文,以供参考:它是非常标准的,遵循示例代码。

int ret;

avformat_alloc_output_context2(&outputFormatCtx, nullptr, nullptr, outFilePath.c_str());

av_dict_set(&outputFormatCtx->metadata, "comment", "FFmpeg Export", 0);

if (!outputFormatCtx)
{
    LOG_AND_THROW("Could not allocate output context");
}

outputVideoStream = avformat_new_stream(outputFormatCtx, nullptr);
outputVideoStream->time_base = AVRational{ 1, AV_TIME_BASE }; // Stream timebase will be used by codec

if (!outputVideoStream)
{
    LOG_AND_THROW("Failed allocating output stream");
}

// defaults to "libx264"
AVCodec *outCodec = avcodec_find_encoder_by_name(selectedCodecName.c_str());

if (!outCodec)
{
    LOG_AND_THROW("Failed finding output codec");
}

AVDictionary *opts = nullptr;

if (selectedCodecName == "libx264")
{
    opts = getX264CodecOptions();
}

encoderCtx = avcodec_alloc_context3(outCodec);

if (!encoderCtx)
{
    LOG_AND_THROW("Failed to allocate the encoder context");
}

encoderCtx->width = width;
encoderCtx->height = height;
encoderCtx->pix_fmt = AV_PIX_FMT_YUV420P;
// time base for the frames we will provide to the encoder
encoderCtx->time_base = AVRational{ 1, AV_TIME_BASE };
// convert framerate from double to rational
encoderCtx->framerate = AVRational{ (int)(frameRate * AV_TIME_BASE), AV_TIME_BASE};

// Match encoderCtx time base for the stream
outputVideoStream->time_base = encoderCtx->time_base;

ret = avcodec_open2(encoderCtx, outCodec, &opts);

if (ret < 0)
{
    LOG_AND_THROW_PARAM("Cannot open video encoder for stream: %d", ret);
}

// Fill in some params for MP4 stream, details about encoder
ret = avcodec_parameters_from_context(outputVideoStream->codecpar, encoderCtx);

if (ret < 0)
{
    LOG_AND_THROW_PARAM("Failed to copy encoder parameters to output stream: %d", ret);
}

if (outputFormatCtx->oformat->flags & AVFMT_GLOBALHEADER)
{
    encoderCtx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
}

av_dump_format(outputFormatCtx, 0, filePath.c_str(), 1);

// End of encoder settings, setting up MP4
if (!(outputFormatCtx->oformat->flags & AVFMT_NOFILE))
{
    ret = avio_open(&outputFormatCtx->pb, outFilePath.c_str(), AVIO_FLAG_WRITE);

    if (ret < 0)
    {
        LOG_AND_THROW_PARAMSTR("Could not open output file '%s'", outFilePath.c_str());
    }
}

ret = avformat_write_header(outputFormatCtx, nullptr);

if (ret < 0)
{
    LOG_AND_THROW_PARAM("Error occurred when opening output file for writing: %d", ret);
}

任何人都可以帮我弄清楚为什么容器没有正常播放?

提前致谢。

-James

0 个答案:

没有答案