【问题标题】:ffmpeg API h264 encoded video does not play on all platformsffmpeg API h264 编码的视频不能在所有平台上播放
【发布时间】:2012-07-17 06:42:21
【问题描述】:

编辑:在之前的版本中,我使用了一个非常古老的 ffmpeg API。我现在使用最新的库。问题只是略有变化,从“主要”变为“高”。

我正在使用 ffmpeg C API 在 C++ 中创建一个 mp4 视频。

我希望生成的视频具有“受约束的基线”配置文件,以便生成的视频可以在尽可能多的平台上播放,尤其是移动设备,但我每次都获得“高”配置文件,即使我很努力将编解码器配置文件编码为 FF_PROFILE_H264_CONSTRAINED_BASELINE。因此,视频无法在我们所有的测试平台上播放。

这就是“ffprobe video.mp4 -show_streams”告诉我的视频流:

  Metadata:
major_brand     : isom
minor_version   : 512
compatible_brands: isomiso2avc1mp41
creation_time   : 1970-01-01 00:00:00
encoder         : Lavf53.5.0
  Duration: 00:00:13.20, start: 0.000000, bitrate: 553 kb/s
Stream #0:0(und): Video: h264 (Main) (avc1 / 0x31637661), yuv420p, 320x180,
424 kb/s, 15 fps, 15 tbr, 15 tbn, 30 tbc
Metadata:
  creation_time   : 1970-01-01 00:00:00
  handler_name    : VideoHandler
Stream #0:1(und): Audio: aac (mp4a / 0x6134706D), 44100 Hz, stereo, s16, 12
kb/s
Metadata:
  creation_time   : 1970-01-01 00:00:00
  handler_name    : SoundHandler
-------VIDEO STREAM--------
[STREAM] 
index=0
codec_name=h264
codec_long_name=H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10

profile=High <-- This should be "Constrained Baseline"

codec_type=video
codec_time_base=1/30
codec_tag_string=avc1
codec_tag=0x31637661
width=320
height=180
has_b_frames=0
sample_aspect_ratio=N/A
display_aspect_ratio=N/A
pix_fmt=yuv420p
level=30
timecode=N/A
is_avc=1
nal_length_size=4
id=N/A
r_frame_rate=15/1
avg_frame_rate=15/1
time_base=1/15
start_time=0.000000
duration=13.200000
bit_rate=424252
nb_frames=198
nb_read_frames=N/A
nb_read_packets=N/A
TAG:creation_time=1970-01-01 00:00:00
TAG:language=und
TAG:handler_name=VideoHandler
[/STREAM]
-------AUDIO STREAM--------
[STREAM]
index=1
codec_name=aac
codec_long_name=Advanced Audio Coding
profile=unknown
codec_type=audio
codec_time_base=1/44100
codec_tag_string=mp4a
codec_tag=0x6134706d
sample_fmt=s16
sample_rate=44100
channels=2
bits_per_sample=0
id=N/A
r_frame_rate=0/0
avg_frame_rate=0/0
time_base=1/44100
start_time=0.000000
duration=13.165714
bit_rate=125301
nb_frames=567
nb_read_frames=N/A
nb_read_packets=N/A
TAG:creation_time=1970-01-01 00:00:00
TAG:language=und
TAG:handler_name=SoundHandler
[/STREAM]

这是我用来添加视频流的功能。来自 ptr-> 的所有值都是从外部定义的,这些值是否必须是特定值才能获得正确的配置文件?:

static AVStream *add_video_stream( Cffmpeg_dll * ptr, AVFormatContext *oc, enum   CodecID codec_id )
{
AVCodecContext *c;
AVStream *st;  
AVCodec* codec;

// Get correct codec
codec = avcodec_find_encoder(codec_id);
if (!codec) {
    av_log(NULL, AV_LOG_ERROR, "%s","Video codec not found\n");
    exit(1);
}

// Create stream
st = avformat_new_stream(oc, codec);
if (!st) {
    av_log(NULL, AV_LOG_ERROR, "%s","Could not alloc stream\n");
    exit(1);
}

c = st->codec;

/* Get default values */
codec = avcodec_find_encoder(codec_id);
if (!codec) {
    av_log(NULL, AV_LOG_ERROR, "%s","Video codec not found (default values)\n");
    exit(1);
}
avcodec_get_context_defaults3(c, codec);

c->codec_id = codec_id;
c->codec_type = AVMEDIA_TYPE_VIDEO;

c->bit_rate = ptr->video_bit_rate;
av_log(NULL, AV_LOG_ERROR, " Bit rate: %i", c->bit_rate);

    c->qmin = ptr->qmin;
    c->qmax = ptr->qmax;
    c->me_method = ptr->me_method;
    c->me_subpel_quality = ptr->me_subpel_quality;
    c->i_quant_factor = ptr->i_quant_factor;
    c->qcompress = ptr->qcompress;
    c->max_qdiff = ptr->max_qdiff;

    // We need to set the level and profile to get videos that play (hopefully) on all platforms
    c->level = 30;
    c->profile = FF_PROFILE_H264_CONSTRAINED_BASELINE;

c->width = ptr->dstWidth; 
c->height = ptr->dstHeight; 

c->time_base.den = ptr->fps;
c->time_base.num = 1;
c->gop_size = ptr->fps;
c->pix_fmt = STREAM_PIX_FMT;
c->max_b_frames = 0;

// some formats want stream headers to be separate
if(oc->oformat->flags & AVFMT_GLOBALHEADER)
    c->flags |= CODEC_FLAG_GLOBAL_HEADER;

return st;
}

其他信息:

作为参考视频,我使用 Mozilla 提供的 gizmo.mp4 作为在每个平台/浏览器上播放的示例。它绝对具有“受约束的基线”配置文件,并且绝对适用于我们所有的测试智能手机。 You can download it here.我们自己制作的视频并非在所有平台上都可以播放,我确信这是因为个人资料。

在创建 mp4 后,我还使用 qt-faststart.exe 将标题移动到文件的开头,因为这不能直接在 C++ 中很好地完成。会不会是这个问题?

显然,我做错了某事,但我不知道会是什么。我会感谢每一个提示;)

【问题讨论】:

  • 您可能应该在 ffmpeg 邮件列表上提交错误报告。正如您所期望的,这应该作为基线或基线受限的信号。
  • 我更新了我的 ffmpeg 版本,问题从“主要”略微改变为现在的“高”配置文件。如果无法解决,@SilverbackNet 会这样做。
  • 有趣的是,当您通过命令行使用 ffmpeg.exe 并设置“-vprofile baseline”时,它按预期工作。我们对 ffmpeg.exe 和我们使用的 C 库使用相同的 ffmpeg 版本。
  • 这意味着问题不在库本身,这是个好消息。您需要做的就是查看 ffmpeg(可执行文件)的源代码,了解他们如何将 h264 正确设置为基线。
  • 我试过了,但理解 ffmpeg 源代码中到底发生了什么可能需要数周时间。肯定没有检查某些值是否为“基线”(我查看了 TextCrawler)。

标签: encoding ffmpeg h.264 libavcodec


【解决方案1】:

我有办法。在 ffmpeg 错误跟踪器中花费了一些时间和讨论并浏览了配置文件设置示例后,我终于找到了解决方案。

需要使用 av_opt_set(codecContext->priv_data, "profile", "baseline" (或任何其他所需的配置文件), AV_OPT_SEARCH_CHILDREN)

所以在我的情况下是:

错误:

// We need to set the level and profile to get videos that play (hopefully) on all platforms
c->level = 30;
c->profile = FF_PROFILE_H264_CONSTRAINED_BASELINE;

正确:

// Set profile to baseline
av_opt_set(c->priv_data, "profile", "baseline", AV_OPT_SEARCH_CHILDREN);

完全不直观且与 API 的其他用法相反,但这是 ffmpeg 的理念。你不需要了解它,你只需要了解如何使用它;)

【讨论】:

  • 为什么选择profile baseline?你的意思是profile constrainted_baseline的视频在某些设备上无法正常播放?
  • "baseline" 实际上最终成为结果文件中的约束基线。
  • 据我所知,baseline 和 constrained_baseline 是 h264 的 2 个不同配置文件。你有什么看法?
  • 我同意你的看法,至少有不同级别的基线配置文件。但正如我所说,将“基线”放入“配置文件”字段会产生一个基线受限的文件。我从来没有真正打扰过更多,因为它有效。
猜你喜欢
  • 2018-10-15
  • 2015-02-23
  • 2016-07-17
  • 2020-12-24
  • 1970-01-01
  • 2013-12-14
  • 1970-01-01
  • 1970-01-01
  • 2015-04-13
相关资源
最近更新 更多