ffmpeg代码实现自定义decoder

59 篇文章 25 订阅
2 篇文章 0 订阅

1、概述

本文主要讲述如何用ffmpeg代码实现自己的decoder。

2、代码

/* 
*本程序主要实现一个自己的decoder并加入到decoder链中去,供api调用
*作者:缪国凯(MK) 
*821486004@qq.com 
*2015-6-4 
*/ 

#include "stdafx.h"

#ifdef __cplusplus
extern "C"
{
#endif
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libavutil/pixdesc.h>
#
#ifdef __cplusplus
};
#endif

#pragma comment(lib, "avcodec.lib")
#pragma comment(lib, "avformat.lib")
#pragma comment(lib, "avutil.lib")
//#pragma comment(lib, "avdevice.lib")
//#pragma comment(lib, "avfilter.lib")
//#pragma comment(lib, "postproc.lib")
//#pragma comment(lib, "swresample.lib")
//#pragma comment(lib, "swscale.lib")

static av_cold int mk_init_decoder(AVCodecContext *avctx)
{
	return 0;
}

static int mk_decode(AVCodecContext *avctx, void *data, int *got_frame,
	AVPacket *avpkt)
{
	AVFrame   *frame   = (AVFrame*)data;
	AVPicture *picture = (AVPicture*)data;
	const uint8_t *buf             = avpkt->data;
	int buf_size                   = avpkt->size;

	int size = avpicture_get_size(avctx->pix_fmt, avctx->width,
		avctx->height);

	frame->pict_type        = AV_PICTURE_TYPE_I;
	frame->key_frame        = 1;
	
	frame->buf[0] = av_buffer_alloc(size);
	
	memcpy(frame->buf[0]->data, buf, buf_size);

	int res = 0;
	if ((res = avpicture_fill(picture, frame->buf[0]->data, avctx->pix_fmt,
		avctx->width, avctx->height)) < 0) 
	{
			av_buffer_unref(&frame->buf[0]);
			return res;
	}

	*got_frame = 1;
	return 0;
}

static av_cold int mk_close_decoder(AVCodecContext *avctx)
{
	return 0;
}

AVCodec ff_mkvideo_decoder = {
	/*.name           = */"mkvideo",
	/*.long_name      = */"mk video",
	/*.type           = */AVMEDIA_TYPE_VIDEO,
	/*.id             = */AV_CODEC_ID_MKVIDEO,
	/*.capabilities	= */CODEC_CAP_PARAM_CHANGE,
	/*.supported_framerates = */NULL,
	/*.pix_fmts		= */NULL,
	/*.supported_samplerates = */NULL,
	/*.sample_fmts	= */NULL,
	/*.channel_layouts = */NULL,
	/*.max_lowres		= */0,
	/*.priv_class		= */NULL,
	/*.profiles		= */NULL,
	/*.priv_data_size	= */0,
	/*.next			= */NULL,
	/*.init_thread_copy = */NULL,
	/*.update_thread_context = */NULL,
	/*.defaults		= */NULL,
	/*.init_static_data = */NULL,	
	/*.init           = */mk_init_decoder,
	/*.encode_sub		= */NULL,
	/*.encode2        = */NULL,
	/*.decode			= */mk_decode,
	/*.close          = */mk_close_decoder,
};

void help()
{
	printf("**********************************************\n");
	printf("Usage:\n");
	printf("    MyMuxer [inputfile.mk] [outputfile] [size]\n");
	printf("\n");
	printf("Examples: \n");
	printf("    MyMuxer a.mk a.avi 1280x720\n");
	printf("**********************************************\n");  
}


int _tmain(int argc, _TCHAR* argv[])
{
	if(argc < 4|| (!strcmp(argv[1],"--help")))
	{
		help();
		return 0;
	}

	av_register_all();
	avcodec_register(&ff_mkvideo_decoder);

	AVFormatContext *in_fxt = NULL, *out_fxt = NULL;
	AVStream *out_stream = NULL;
	int video_index = -1;

	AVDictionary *param = 0;
	av_dict_set(¶m, "video_size", argv[3], 0);
	if (avformat_open_input(&in_fxt, argv[1], NULL, ¶m) < 0)
	{
		printf("can not open the input file context!\n");
		goto end;
	}
	if (avformat_find_stream_info(in_fxt, NULL) < 0)
	{
		printf("can not find the stream info!\n");
		goto end;
	}

	if(avformat_alloc_output_context2(&out_fxt, NULL, NULL, argv[2]) < 0)
	{
		printf("can not alloc output context!\n");
		goto end;
	}

	for (int i = 0; i < in_fxt->nb_streams; i++)
	{
		if (in_fxt->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
		{
			//open decoder
			AVCodec *codec = avcodec_find_decoder(AV_CODEC_ID_MKVIDEO);
			//由于ffmpeg源码里 还没把mk demuxer的codecid改过来,所以这里强制赋值,不然avcodec_open2打不开
			in_fxt->streams[i]->codec->codec_id = AV_CODEC_ID_MKVIDEO;
			if(0 > avcodec_open2(in_fxt->streams[i]->codec, codec, NULL))
			{
				printf("can not find or open decoder!\n");
				goto end;
			}
			video_index = i;
			//new stream
			out_stream = avformat_new_stream(out_fxt, NULL);
			if (!out_stream)
			{
				printf("can not new stream for output!\n");
				goto end;
			}
			//set codec context param
			out_stream->codec->codec = avcodec_find_encoder(out_fxt->oformat->video_codec);
			out_stream->codec->height = in_fxt->streams[i]->codec->height;
			out_stream->codec->width = in_fxt->streams[i]->codec->width;

			out_stream->codec->time_base = in_fxt->streams[i]->time_base;
			//out_stream->codec->time_base.den = 25;

			out_stream->codec->sample_aspect_ratio = in_fxt->streams[i]->codec->sample_aspect_ratio;			
			out_stream->codec->pix_fmt = in_fxt->streams[i]->codec->pix_fmt;

			out_stream->avg_frame_rate.den = out_stream->codec->time_base.num;
			out_stream->avg_frame_rate.num = out_stream->codec->time_base.den;
			if (!out_stream->codec->codec)
			{
				printf("can not find the encoder!\n");
				goto end;
			}
			if ((avcodec_open2(out_stream->codec, out_stream->codec->codec, NULL)) < 0)
			{
				printf("can not open the encoder\n");
				goto end;
			}
			if (out_fxt->oformat->flags & AVFMT_GLOBALHEADER)
				out_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
			break;
		}
	}

	if (-1 == video_index)
	{
		printf("found no video stream in input file!\n");
		goto end;
	}

	if (!(out_fxt->oformat->flags & AVFMT_NOFILE))
	{
		if(avio_open(&out_fxt->pb, argv[2], AVIO_FLAG_WRITE) < 0)
		{
			printf("can not open output file handle!\n");
			goto end;
		}
	}

	if(avformat_write_header(out_fxt, NULL) < 0)
	{
		printf("can not write the header of the output file!\n");
		goto end;
	}

	AVPacket pkt_in, pkt_out;
	
	av_init_packet(&pkt_in);
	av_init_packet(&pkt_out);
	int got_frame, got_picture;
	int i = 0, frame_index = 0;
	while(1)
	{
		AVFrame *frame;
		frame = av_frame_alloc();
		got_frame = -1;
		got_picture = -1;
		if (av_read_frame(in_fxt, &pkt_in) < 0)
		{
			break;
		}frame->buf;
		if (avcodec_decode_video2(in_fxt->streams[video_index]->codec, frame, &got_frame, &pkt_in) < 0)
		{
			printf("can not decoder a frame");
			break;
		}
		av_free_packet(&pkt_in);

		if (got_frame)
		{
			frame->pts = i++;
			pkt_out.data = NULL;//主要这里必须自己初始化,或者必须置为null,不然ff_alloc_packet2函数会报错
			pkt_out.size = 0;
			if (avcodec_encode_video2(out_stream->codec, &pkt_out, frame, &got_picture) < 0)
			{
				printf("can not encode a frame!\n");
				break;
			}

			if (got_picture)
			{
				printf("Succeed to encode frame: %5d\tsize:%5d\n",frame_index,pkt_out.size);
				pkt_out.stream_index = out_stream->index;
				frame_index++;
				av_write_frame(out_fxt, &pkt_out);
				av_free_packet(&pkt_out);
			}
		}
		av_frame_free(&frame);
	}
	

	av_write_trailer(out_fxt);

	//clean
	avcodec_close(out_stream->codec);
	avcodec_close(out_fxt->streams[video_index]->codec);
end:
	avformat_close_input(&in_fxt);

	if (out_fxt && !(out_fxt->oformat->flags & AVFMT_NOFILE))
	{
		avio_close(out_fxt->pb);
	}
	avformat_free_context(out_fxt);
	return 0;
}

3、解释

原理和前面的自定义的muxer、demuxer、encoder一样,在这里就不多说了。
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dancing_night

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值