1. 程式人生 > >ffmpeg實戰系列——002

ffmpeg實戰系列——002

temporary sse setup 一個 cond strong param av_free length

Talk is cheap,Show me the code!

示例1、decode_video.c

int main(int argc, char **argv)

{

const char *filename, *outfilename;

const AVCodec *codec;

AVCodecContext *c= NULL;

int frame_count;

FILE *f;

AVFrame *frame;

uint8_t inbuf[INBUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE];

AVPacket avpkt;

filename = argv[1];

outfilename = argv[2];

avcodec_register_all();

av_init_packet(&avpkt);

codec = avcodec_find_decoder(AV_CODEC_ID_MPEG1VIDEO);

c = avcodec_alloc_context3(codec);

if (avcodec_open2(c, codec, NULL) < 0) {

}

frame = av_frame_alloc();

frame_count = 0;

for (;;) {

avpkt.size = fread(inbuf, 1, INBUF_SIZE, f);

avpkt.data = inbuf;

while (avpkt.size > 0)

if (decode_write_frame(outfilename, c, frame, &frame_count, &avpkt, 0) < 0)

exit(1);

}

avpkt.data = NULL;

avpkt.size = 0;

decode_write_frame(outfilename, c, frame, &frame_count, &avpkt, 1);

fclose(f);

avcodec_free_context(&c);

av_frame_free(&frame);

return 0;

}

static int decode_write_frame(const char *outfilename, AVCodecContext *avctx,

AVFrame *frame, int *frame_count, AVPacket *pkt, int last)

{

len = avcodec_decode_video2(avctx, frame, &got_frame, pkt);

return 0;

}

下面分析該例子涉及的幾個數據結構:

1、AVPacket avpkt;

typedef struct AVPacket {

AVBufferRef *buf;

int64_t pts;

int64_t dts;

uint8_t *data;

int size;

int stream_index;

int flags;

AVPacketSideData *side_data;

int side_data_elems;

int64_t duration;

int64_t pos; ///< byte position in stream, -1 if unknown

} AVPacket;

2、AVFrame *frame;

typedef struct AVFrame {

uint8_t *data[AV_NUM_DATA_POINTERS];

int linesize[AV_NUM_DATA_POINTERS];

uint8_t **extended_data;

int width, height;

int nb_samples;

int format;

int key_frame;

enum AVPictureType pict_type;

AVRational sample_aspect_ratio;

int64_t pts;

int64_t pkt_dts;

int coded_picture_number;

int display_picture_number;

int quality;

void *opaque;

int repeat_pict;

int interlaced_frame;

int top_field_first;

int palette_has_changed;

int64_t reordered_opaque;

int sample_rate;

uint64_t channel_layout;

AVBufferRef *buf[AV_NUM_DATA_POINTERS];

AVBufferRef **extended_buf;

int nb_extended_buf;

AVFrameSideData **side_data;

int nb_side_data;

int flags;

enum AVColorRange color_range;

enum AVColorPrimaries color_primaries;

enum AVColorTransferCharacteristic color_trc;

enum AVColorSpace colorspace;

enum AVChromaLocation chroma_location;

int64_t best_effort_timestamp;

int64_t pkt_pos;

int64_t pkt_duration;

AVDictionary *metadata;

int decode_error_flags;

int channels;

int pkt_size;

AVBufferRef *hw_frames_ctx;

AVBufferRef *opaque_ref;

} AVFrame;

3、const AVCodec *codec;

codec = avcodec_find_decoder(AV_CODEC_ID_MPEG1VIDEO);

AVCodec *avcodec_find_decoder(enum AVCodecID id)

{

return find_encdec(id, 0);

}

static AVCodec *find_encdec(enum AVCodecID id, int encoder)

{

AVCodec *p, *experimental = NULL;

p = first_avcodec;

id= remap_deprecated_codec_id(id);

while (p) {

if ((encoder ? av_codec_is_encoder(p) : av_codec_is_decoder(p)) &&

p->id == id) {

if (p->capabilities & AV_CODEC_CAP_EXPERIMENTAL && !experimental) {

experimental = p;

} else

return p;

}

p = p->next;

}

return experimental;

}

AVCodec ff_mpeg1video_decoder = {

.name = "mpeg1video",

.long_name = NULL_IF_CONFIG_SMALL("MPEG-1 video"),

.type = AVMEDIA_TYPE_VIDEO,

.id = AV_CODEC_ID_MPEG1VIDEO,

.priv_data_size = sizeof(Mpeg1Context),

.init = mpeg_decode_init,

.close = mpeg_decode_end,

.decode = mpeg_decode_frame,

.capabilities = AV_CODEC_CAP_DRAW_HORIZ_BAND | AV_CODEC_CAP_DR1 |

AV_CODEC_CAP_TRUNCATED | AV_CODEC_CAP_DELAY |

AV_CODEC_CAP_SLICE_THREADS,

.caps_internal = FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM,

.flush = flush,

.max_lowres = 3,

.update_thread_context = ONLY_IF_THREADS_ENABLED(mpeg_decode_update_thread_context)

};

這裏順便介紹一下:

typedef struct Mpeg1Context {

MpegEncContext mpeg_enc_ctx;

int mpeg_enc_ctx_allocated; /* true if decoding context allocated */

int repeat_field; /* true if we must repeat the field */

AVPanScan pan_scan; /* some temporary storage for the panscan */

AVStereo3D stereo3d;

int has_stereo3d;

uint8_t *a53_caption;

int a53_caption_size;

uint8_t afd;

int has_afd;

int slice_count;

AVRational save_aspect;

int save_width, save_height, save_progressive_seq;

AVRational frame_rate_ext; /* MPEG-2 specific framerate modificator */

int sync; /* Did we reach a sync point like a GOP/SEQ/KEYFrame? */

int tmpgexs;

int first_slice;

int extradata_decoded;

} Mpeg1Context;

所以如果你要調用AVCodec ff_mpeg1video_decoder幫你幹活,你首先要有一個Mpeg1Context,因為ff_mpeg1video_decoder的所有數據都來源於Mpeg1Context。而Mpeg1Context是在decode init的時候初始化的。

4、AVCodecContext *c= NULL;

c = avcodec_alloc_context3(codec);

AVCodecContext *avcodec_alloc_context3(const AVCodec *codec)

{

AVCodecContext *avctx= av_malloc(sizeof(AVCodecContext));

if (!avctx)

return NULL;

if (init_context_defaults(avctx, codec) < 0) {

av_free(avctx);

return NULL;

}

return avctx;

}

static int init_context_defaults(AVCodecContext *s, const AVCodec *codec)

{

int flags=0;

memset(s, 0, sizeof(AVCodecContext));

s->av_class = &av_codec_context_class;

s->codec_type = codec ? codec->type : AVMEDIA_TYPE_UNKNOWN;

if (codec) {

s->codec = codec;

s->codec_id = codec->id;

}

if(s->codec_type == AVMEDIA_TYPE_AUDIO)

flags= AV_OPT_FLAG_AUDIO_PARAM;

else if(s->codec_type == AVMEDIA_TYPE_VIDEO)

flags= AV_OPT_FLAG_VIDEO_PARAM;

else if(s->codec_type == AVMEDIA_TYPE_SUBTITLE)

flags= AV_OPT_FLAG_SUBTITLE_PARAM;

av_opt_set_defaults2(s, flags, flags);

s->time_base = (AVRational){0,1};

s->framerate = (AVRational){ 0, 1 };

s->pkt_timebase = (AVRational){ 0, 1 };

s->get_buffer2 = avcodec_default_get_buffer2;

s->get_format = avcodec_default_get_format;

s->execute = avcodec_default_execute;

s->execute2 = avcodec_default_execute2;

s->sample_aspect_ratio = (AVRational){0,1};

s->pix_fmt = AV_PIX_FMT_NONE;

s->sw_pix_fmt = AV_PIX_FMT_NONE;

s->sample_fmt = AV_SAMPLE_FMT_NONE;

s->reordered_opaque = AV_NOPTS_VALUE;

if(codec && codec->priv_data_size){

if(!s->priv_data){

s->priv_data= av_mallocz(codec->priv_data_size);

if (!s->priv_data) {

return AVERROR(ENOMEM);

}

}

if(codec->priv_class){

*(const AVClass**)s->priv_data = codec->priv_class;

av_opt_set_defaults(s->priv_data);

}

}

if (codec && codec->defaults) {

int ret;

const AVCodecDefault *d = codec->defaults;

while (d->key) {

ret = av_opt_set(s, d->key, d->value, 0);

av_assert0(ret >= 0);

d++;

}

}

return 0;

}

5、avcodec_open2(c, codec, NULL)

初始化一些avcodeccontext的成員變量,最重要的是初始化解碼器:

ret = avctx->codec->init(avctx);

//legacy decoder

AVCodec ff_mpegvideo_decoder = {

.name = "mpegvideo",

.long_name = NULL_IF_CONFIG_SMALL("MPEG-1 video"),

.type = AVMEDIA_TYPE_VIDEO,

.id = AV_CODEC_ID_MPEG2VIDEO,

.priv_data_size = sizeof(Mpeg1Context),

.init = mpeg_decode_init,

.close = mpeg_decode_end,

.decode = mpeg_decode_frame,

.capabilities = AV_CODEC_CAP_DRAW_HORIZ_BAND | AV_CODEC_CAP_DR1 | AV_CODEC_CAP_TRUNCATED | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_SLICE_THREADS,

.caps_internal = FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM,

.flush = flush,

.max_lowres = 3,

};

這個太復雜,換一個H264的解碼器吧,其實是一樣的:

AVCodec ff_h264_decoder = {

.name = "h264",

.long_name = NULL_IF_CONFIG_SMALL("H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10"),

.type = AVMEDIA_TYPE_VIDEO,

.id = AV_CODEC_ID_H264,

.priv_data_size = sizeof(H264Context),

.init = ff_h264_decode_init,

.close = h264_decode_end,

.decode = h264_decode_frame,

.capabilities = /*AV_CODEC_CAP_DRAW_HORIZ_BAND |*/ AV_CODEC_CAP_DR1 |

AV_CODEC_CAP_DELAY | AV_CODEC_CAP_SLICE_THREADS |

AV_CODEC_CAP_FRAME_THREADS,

.caps_internal = FF_CODEC_CAP_INIT_THREADSAFE,

.flush = flush_dpb,

.init_thread_copy = ONLY_IF_THREADS_ENABLED(decode_init_thread_copy),

.update_thread_context = ONLY_IF_THREADS_ENABLED(ff_h264_update_thread_context),

.profiles = NULL_IF_CONFIG_SMALL(ff_h264_profiles),

.priv_class = &h264_class,

};

av_cold int ff_h264_decode_init(AVCodecContext *avctx)

{

H264Context *h = avctx->priv_data;

int ret;

ret = h264_init_context(avctx, h);

if (ret < 0)

return ret;

ret = ff_thread_once(&h264_vlc_init, ff_h264_decode_init_vlc);

if (ret != 0) {

av_log(avctx, AV_LOG_ERROR, "pthread_once has failed.");

return AVERROR_UNKNOWN;

}

if (avctx->ticks_per_frame == 1) {

if(h->avctx->time_base.den < INT_MAX/2) {

h->avctx->time_base.den *= 2;

} else

h->avctx->time_base.num /= 2;

}

avctx->ticks_per_frame = 2;

if (avctx->extradata_size > 0 && avctx->extradata) {

ret = ff_h264_decode_extradata(avctx->extradata, avctx->extradata_size,

&h->ps, &h->is_avc, &h->nal_length_size,

avctx->err_recognition, avctx);

if (ret < 0) {

h264_decode_end(avctx);

return ret;

}

}

if (h->ps.sps && h->ps.sps->bitstream_restriction_flag &&

h->avctx->has_b_frames < h->ps.sps->num_reorder_frames) {

h->avctx->has_b_frames = h->ps.sps->num_reorder_frames;

}

avctx->internal->allocate_progress = 1;

ff_h264_flush_change(h);

if (h->enable_er < 0 && (avctx->active_thread_type & FF_THREAD_SLICE))

h->enable_er = 0;

if (h->enable_er && (avctx->active_thread_type & FF_THREAD_SLICE)) {

av_log(avctx, AV_LOG_WARNING,

"Error resilience with slice threads is enabled. It is unsafe and unsupported and may crash. "

"Use it at your own risk\n");

}

return 0;

}

//初始化解碼器的上下文,非常關鍵。之後解碼所有的信息來源都是這裏

static int h264_init_context(AVCodecContext *avctx, H264Context *h)

{

int i;

h->avctx = avctx;

h->cur_chroma_format_idc = -1;

h->picture_structure = PICT_FRAME;

h->workaround_bugs = avctx->workaround_bugs;

h->flags = avctx->flags;

h->poc.prev_poc_msb = 1 << 16;

h->recovery_frame = -1;

h->frame_recovered = 0;

h->poc.prev_frame_num = -1;

h->sei.frame_packing.frame_packing_arrangement_cancel_flag = -1;

h->sei.unregistered.x264_build = -1;

h->next_outputed_poc = INT_MIN;

for (i = 0; i < MAX_DELAYED_PIC_COUNT; i++)

h->last_pocs[i] = INT_MIN;

ff_h264_sei_uninit(&h->sei);

avctx->chroma_sample_location = AVCHROMA_LOC_LEFT;

h->nb_slice_ctx = (avctx->active_thread_type & FF_THREAD_SLICE) ? avctx->thread_count : 1;

h->slice_ctx = av_mallocz_array(h->nb_slice_ctx, sizeof(*h->slice_ctx));

if (!h->slice_ctx) {

h->nb_slice_ctx = 0;

return AVERROR(ENOMEM);

}

for (i = 0; i < H264_MAX_PICTURE_COUNT; i++) {

h->DPB[i].f = av_frame_alloc();

if (!h->DPB[i].f)

return AVERROR(ENOMEM);

}

h->cur_pic.f = av_frame_alloc();

if (!h->cur_pic.f)

return AVERROR(ENOMEM);

h->last_pic_for_ec.f = av_frame_alloc();

if (!h->last_pic_for_ec.f)

return AVERROR(ENOMEM);

for (i = 0; i < h->nb_slice_ctx; i++)

h->slice_ctx[i].h264 = h;

return 0;

}

6、解碼:

ret = avctx->codec->decode(avctx, picture, got_picture_ptr,

&tmp);

static int h264_decode_frame(AVCodecContext *avctx, void *data,

int *got_frame, AVPacket *avpkt)

{

const uint8_t *buf = avpkt->data;

int buf_size = avpkt->size;

H264Context *h = avctx->priv_data;

AVFrame *pict = data;

int buf_index;

int ret;

h->flags = avctx->flags;

h->setup_finished = 0;

h->nb_slice_ctx_queued = 0;

ff_h264_unref_picture(h, &h->last_pic_for_ec);

/* end of stream, output what is still in the buffers */

if (buf_size == 0)

return send_next_delayed_frame(h, pict, got_frame, 0);

if (h->is_avc && av_packet_get_side_data(avpkt, AV_PKT_DATA_NEW_EXTRADATA, NULL)) {

int side_size;

uint8_t *side = av_packet_get_side_data(avpkt, AV_PKT_DATA_NEW_EXTRADATA, &side_size);

if (is_extra(side, side_size))

ff_h264_decode_extradata(side, side_size,

&h->ps, &h->is_avc, &h->nal_length_size,

avctx->err_recognition, avctx);

}

if(h->is_avc && buf_size >= 9 && buf[0]==1 && buf[2]==0 && (buf[4]&0xFC)==0xFC && (buf[5]&0x1F) && buf[8]==0x67){

if (is_extra(buf, buf_size))

return ff_h264_decode_extradata(buf, buf_size,

&h->ps, &h->is_avc, &h->nal_length_size,

avctx->err_recognition, avctx);

}

buf_index = decode_nal_units(h, buf, buf_size);

if (buf_index < 0)

return AVERROR_INVALIDDATA;

if (!h->cur_pic_ptr && h->nal_unit_type == H264_NAL_END_SEQUENCE) {

av_assert0(buf_index <= buf_size);

return send_next_delayed_frame(h, pict, got_frame, buf_index);

}

if (!(avctx->flags2 & AV_CODEC_FLAG2_CHUNKS) && (!h->cur_pic_ptr || !h->has_slice)) {

if (avctx->skip_frame >= AVDISCARD_NONREF ||

buf_size >= 4 && !memcmp("Q264", buf, 4))

return buf_size;

av_log(avctx, AV_LOG_ERROR, "no frame!\n");

return AVERROR_INVALIDDATA;

}

if (!(avctx->flags2 & AV_CODEC_FLAG2_CHUNKS) ||

(h->mb_y >= h->mb_height && h->mb_height)) {

if ((ret = ff_h264_field_end(h, &h->slice_ctx[0], 0)) < 0)

return ret;

/* Wait for second field. */

if (h->next_output_pic) {

ret = finalize_frame(h, pict, h->next_output_pic, got_frame);

if (ret < 0)

return ret;

}

}

av_assert0(pict->buf[0] || !*got_frame);

ff_h264_unref_picture(h, &h->last_pic_for_ec);

return get_consumed_bytes(buf_index, buf_size);

}

static int send_next_delayed_frame(H264Context *h, AVFrame *dst_frame,

int *got_frame, int buf_index)

{

int ret, i, out_idx;

H264Picture *out = h->delayed_pic[0];

h->cur_pic_ptr = NULL;

h->first_field = 0;

out_idx = 0;

for (i = 1;

h->delayed_pic[i] &&

!h->delayed_pic[i]->f->key_frame &&

!h->delayed_pic[i]->mmco_reset;

i++)

if (h->delayed_pic[i]->poc < out->poc) {

out = h->delayed_pic[i];

out_idx = i;

}

for (i = out_idx; h->delayed_pic[i]; i++)

h->delayed_pic[i] = h->delayed_pic[i + 1];

if (out) {

out->reference &= ~DELAYED_PIC_REF;

ret = finalize_frame(h, dst_frame, out, got_frame);

if (ret < 0)

return ret;

}

return buf_index;

}

static int finalize_frame(H264Context *h, AVFrame *dst, H264Picture *out, int *got_frame)

{

int ret;

if (((h->avctx->flags & AV_CODEC_FLAG_OUTPUT_CORRUPT) ||

(h->avctx->flags2 & AV_CODEC_FLAG2_SHOW_ALL) ||

out->recovered)) {

if (!h->avctx->hwaccel &&

(out->field_poc[0] == INT_MAX ||

out->field_poc[1] == INT_MAX)

) {

int p;

AVFrame *f = out->f;

int field = out->field_poc[0] == INT_MAX;

uint8_t *dst_data[4];

int linesizes[4];

const uint8_t *src_data[4];

av_log(h->avctx, AV_LOG_DEBUG, "Duplicating field %d to fill missing\n", field);

for (p = 0; p<4; p++) {

dst_data[p] = f->data[p] + (field^1)*f->linesize[p];

src_data[p] = f->data[p] + field *f->linesize[p];

linesizes[p] = 2*f->linesize[p];

}

av_image_copy(dst_data, linesizes, src_data, linesizes,

f->format, f->width, f->height>>1);

}

ret = output_frame(h, dst, out);

if (ret < 0)

return ret;

*got_frame = 1;

if (CONFIG_MPEGVIDEO) {

ff_print_debug_info2(h->avctx, dst, NULL,

out->mb_type,

out->qscale_table,

out->motion_val,

NULL,

h->mb_width, h->mb_height, h->mb_stride, 1);

}

}

return 0;

}

static int output_frame(H264Context *h, AVFrame *dst, H264Picture *srcp)

{

AVFrame *src = srcp->f;

const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(src->format);

int i;

int ret;

if (src->format == AV_PIX_FMT_VIDEOTOOLBOX && src->buf[0]->size == 1)

return AVERROR_EXTERNAL;

ret = av_frame_ref(dst, src);

if (ret < 0)

return ret;

av_dict_set(&dst->metadata, "stereo_mode", ff_h264_sei_stereo_mode(&h->sei.frame_packing), 0);

if (srcp->sei_recovery_frame_cnt == 0)

dst->key_frame = 1;

if (!srcp->crop)

return 0;

for (i = 0; i < desc->nb_components; i++) {

int hshift = (i > 0) ? desc->log2_chroma_w : 0;

int vshift = (i > 0) ? desc->log2_chroma_h : 0;

int off = ((srcp->crop_left >> hshift) << h->pixel_shift) +

(srcp->crop_top >> vshift) * dst->linesize[i];

dst->data[i] += off;

}

return 0;

}

ffmpeg實戰系列——002