php ffmpeg matedata,ffmpeg 3.2官方版本无法传递flv metadata中的bit_rate

FFmpeg官网:

http://www.ffmpeg.org/download.html

现象:

执行如下命令并分析metadata

./ffmpeg -i input.flv -c copy -f flv out.flv

发现out.flv的metadata没有包括input.flv的bitrate信息。

原因:

libavformat/flvdec.c

未能获取到输入音视频的bitrate值。

有两种解决办法:

解决方法一:

flvdec.c回退函数flv_read_header()到ffmpeg3.0版本

static AVStream *create_stream(AVFormatContext *s, int codec_type)

{

AVStream *st = avformat_new_stream(s, NULL);

if (!st)

return NULL;

st->codec->codec_type = codec_type;

if (s->nb_streams>=3 ||( s->nb_streams==2

&& s->streams[0]->codec->codec_type != AVMEDIA_TYPE_SUBTITLE

&& s->streams[1]->codec->codec_type != AVMEDIA_TYPE_SUBTITLE))

s->ctx_flags &= ~AVFMTCTX_NOHEADER;

avpriv_set_pts_info(st, 32, 1, 1000); /* 32 bit pts in ms */

return st;

}

static int flv_read_header(AVFormatContext *s)

{

int offset, flags;

FLVContext *flv = s->priv_data;

avio_skip(s->pb, 4);

flags = avio_r8(s->pb);

s->ctx_flags |= AVFMTCTX_NOHEADER;

if (flags & FLV_HEADER_FLAG_HASVIDEO)

if (!create_stream(s, AVMEDIA_TYPE_VIDEO))

return AVERROR(ENOMEM);

if (flags & FLV_HEADER_FLAG_HASAUDIO)

if (!create_stream(s, AVMEDIA_TYPE_AUDIO))

return AVERROR(ENOMEM);

// Flag doesn't indicate whether or not there is script-data present. Must

// create that stream if it's encountered.

offset = avio_rb32(s->pb);

avio_seek(s->pb, offset, SEEK_SET);

avio_skip(s->pb, 4);

s->start_time = 0;

flv->sum_flv_tag_size = 0;

return 0;

}

则通过函数open_input_file() -> avformat_open_input() -> s->iformat->read_header(s)即可以创建video和audio的stream。然后通过  avformat_find_stream_info() -> read_frame_internal(ic, &pkt1) -> ff_read_packet() -> s->iformat->read_packet(s, pkt),回调函数flv_read_packet(AVFormatContext *s, AVPacket *pkt)获取metadata中的bitrate。

解决方法二:

对于flvdec.c中的代码进行修改

修改前代码:

static int amf_parse_object(AVFormatContext *s, AVStream *astream,

AVStream *vstream, const char *key,

int64_t max_pos, int depth)

{

... ...

if (key) {

apar = astream ? astream->codecpar : NULL;

vpar = vstream ? vstream->codecpar : NULL;

// stream info doesn't live any deeper than the first object

if (depth == 1) {

if (amf_type == AMF_DATA_TYPE_NUMBER ||

amf_type == AMF_DATA_TYPE_BOOL) {

if (!strcmp(key, "duration"))

s->duration = num_val * AV_TIME_BASE;

else if (!strcmp(key, "videodatarate") && vpar &&

0 <= (int)(num_val * 1024.0))

vpar->bit_rate = num_val * 1024.0;

else if (!strcmp(key, "audiodatarate") && apar &&

0 <= (int)(num_val * 1024.0))

apar->bit_rate = num_val * 1024.0;

else if (!strcmp(key, "datastream")) {

AVStream *st = create_stream(s, AVMEDIA_TYPE_SUBTITLE);

if (!st)

return AVERROR(ENOMEM);

st->codecpar->codec_id = AV_CODEC_ID_TEXT;

} else if (flv->trust_metadata) {

if (!strcmp(key, "videocodecid") && vpar) {

flv_set_video_codec(s, vstream, num_val, 0);

} else if (!strcmp(key, "audiocodecid") && apar) {

int id = ((int)num_val) << FLV_AUDIO_CODECID_OFFSET;

flv_set_audio_codec(s, astream, apar, id);

} else if (!strcmp(key, "audiosamplerate") && apar) {

apar->sample_rate = num_val;

} else if (!strcmp(key, "audiosamplesize") && apar) {

apar->bits_per_coded_sample = num_val;

} else if (!strcmp(key, "stereo") && apar) {

apar->channels = num_val + 1;

apar->channel_layout = apar->channels == 2 ?

AV_CH_LAYOUT_STEREO :

AV_CH_LAYOUT_MONO;

} else if (!strcmp(key, "width") && vpar) {

vpar->width = num_val;

} else if (!strcmp(key, "height") && vpar) {

vpar->height = num_val;

}

}

}

if (amf_type == AMF_DATA_TYPE_STRING) {

if (!strcmp(key, "encoder")) {

int version = -1;

if (1 == sscanf(str_val, "Open Broadcaster Software v0.%d", &version)) {

if (version > 0 && version <= 655)

flv->broken_sizes = 1;

}

} else if (!strcmp(key, "metadatacreator") && !strcmp(str_val, "MEGA")) {

flv->broken_sizes = 1;

}

}

... ...

}

修改后代码

typedef struct FLVContext {

const AVClass *class; ///< Class for private options.

int trust_metadata; ///< configure streams according onMetaData

int wrong_dts; ///< wrong dts due to negative cts

uint8_t *new_extradata[FLV_STREAM_TYPE_NB];

int new_extradata_size[FLV_STREAM_TYPE_NB];

int last_sample_rate;

int last_channels;

struct {

int64_t dts;

int64_t pos;

} validate_index[2];

int validate_next;

int validate_count;

int searched_for_end;

uint8_t resync_buffer[2*RESYNC_BUFFER_SIZE];

int broken_sizes;

int sum_flv_tag_size;

int last_keyframe_stream_index;

int keyframe_count;

int64_t *keyframe_times;

int64_t *keyframe_filepositions;

int64_t video_bit_rate;

int64_t audio_bit_rate;

} FLVContext;

static AVStream *create_stream(AVFormatContext *s, int codec_type)

{

FLVContext *flv = s->priv_data;

AVStream *st = avformat_new_stream(s, NULL);

if (!st)

return NULL;

st->codecpar->codec_type = codec_type;

if (codec_type == FLV_STREAM_TYPE_VIDEO)

st->codecpar->bit_rate = flv->video_bit_rate;

if (codec_type == FLV_STREAM_TYPE_AUDIO)

st->codecpar->bit_rate = flv->audio_bit_rate;

if (s->nb_streams>=3 ||( s->nb_streams==2

&& s->streams[0]->codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE

&& s->streams[1]->codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE))

s->ctx_flags &= ~AVFMTCTX_NOHEADER;

avpriv_set_pts_info(st, 32, 1, 1000); /* 32 bit pts in ms */

flv->last_keyframe_stream_index = s->nb_streams - 1;

add_keyframes_index(s);

return st;

}

static int amf_parse_object(AVFormatContext *s, AVStream *astream,

AVStream *vstream, const char *key,

int64_t max_pos, int depth)

{

... ...

if (key) {

apar = astream ? astream->codecpar : NULL;

vpar = vstream ? vstream->codecpar : NULL;

// stream info doesn't live any deeper than the first object

if (depth == 1) {

if (amf_type == AMF_DATA_TYPE_NUMBER ||

amf_type == AMF_DATA_TYPE_BOOL) {

if (!strcmp(key, "duration"))

s->duration = num_val * AV_TIME_BASE;

else if (!strcmp(key, "videodatarate") &&

0 <= (int)(num_val * 1024.0))

flv->video_bit_rate = num_val * 1024.0;

else if (!strcmp(key, "audiodatarate") &&

0 <= (int)(num_val * 1024.0))

flv->audio_bit_rate = num_val * 1024.0;

else if (!strcmp(key, "datastream")) {

AVStream *st = create_stream(s, AVMEDIA_TYPE_SUBTITLE);

if (!st)

return AVERROR(ENOMEM);

st->codecpar->codec_id = AV_CODEC_ID_TEXT;

} else if (flv->trust_metadata) {

if (!strcmp(key, "videocodecid") && vpar) {

flv_set_video_codec(s, vstream, num_val, 0);

} else if (!strcmp(key, "audiocodecid") && apar) {

int id = ((int)num_val) << FLV_AUDIO_CODECID_OFFSET;

flv_set_audio_codec(s, astream, apar, id);

} else if (!strcmp(key, "audiosamplerate") && apar) {

apar->sample_rate = num_val;

} else if (!strcmp(key, "audiosamplesize") && apar) {

apar->bits_per_coded_sample = num_val;

} else if (!strcmp(key, "stereo") && apar) {

apar->channels = num_val + 1;

apar->channel_layout = apar->channels == 2 ?

AV_CH_LAYOUT_STEREO :

AV_CH_LAYOUT_MONO;

} else if (!strcmp(key, "width") && vpar) {

vpar->width = num_val;

} else if (!strcmp(key, "height") && vpar) {

vpar->height = num_val;

}

}

}

if (amf_type == AMF_DATA_TYPE_STRING) {

if (!strcmp(key, "encoder")) {

int version = -1;

if (1 == sscanf(str_val, "Open Broadcaster Software v0.%d", &version)) {

if (version > 0 && version <= 655)

flv->broken_sizes = 1;

}

} else if (!strcmp(key, "metadatacreator") && !strcmp(str_val, "MEGA")) {

flv->broken_sizes = 1;

}

}

... ...

}

结论:

能够成功的将输入flv流中metadata传递到输出metadata。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值