1. 程式人生 > >ffmpeg程式碼實現自定義decoder

ffmpeg程式碼實現自定義decoder

/* 
*本程式主要實現一個自己的decoder並加入到decoder鏈中去,供api呼叫
*作者:繆國凱(MK) 
*[email protected] 
*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;
}

相關推薦

ffmpeg程式碼實現定義decoder

/* *本程式主要實現一個自己的decoder並加入到decoder鏈中去,供api呼叫 *作者:繆國凱(MK) *[email protected] *2015-6-4 */ #include "stdafx.h" #ifdef __cplusplus extern "C" { #e

java實現定義異常例項程式碼

此處主要便於對異常類的使用上方便大家理解以一個公約數為例做了一個簡單自定義異常的處理程式碼如下: 如果操作者輸入數字符合要求程式執行,不符合則丟擲錯誤。 package 自定義異常簡單例項; import java.util.Scanner; public class CommonDivisor

實現定義註解(程式碼篇)

第一:定義三個自定義的註解類 第二:建立一個實體 第三:建立一箇中間類 第四:測試 註解處理的基礎知識 方法1:<T extends Annotation> T getAnnotation(Class<T> annotationClass

JS實現定義簡單網頁軟鍵盤效果程式碼

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html

如何實現定義同步組件

nds 允許 oid try unlock all 同步 while name package com.chen;import java.util.concurrent.TimeUnit;import java.util.concurrent.locks.AbstractQ

JS簡單實現定義右鍵菜單

ans idt 右鍵 動畫 忘記 span spa round 部分 RT,一個簡單的例子,僅僅講述原理 <div id="menu" style="width: 0;height: 0;background: cadetblue;position: absolu

Notification的基本用法以及使用RemoteView實現定義布局

解決 edi ngs 取消 ets lsp 過程 net tde Notification的作用 Notification是一種全局效果的通知,在系統的通知欄中顯示。既然作為通知,其基本作用有: 顯示接收到短消息、即時信息等 顯示客戶端的推送(廣告、優惠、新聞等)

匿名類型與Select方法實現定義對象插入局部表結構中

aso 直接 菜單 ember new order ber 構建 als 在提取局部表結構數據時,通過Select選取需要的字段,如下句,此時其實產生了一個不用於_menuMan的原新數據類型new { c.SYS_COMMANDS_ID,c.TXT_COMMANDTITL

java中實現Comparable接口實現定義排序

static -1 return rabl generated args logs ava sca 1 class Student implements Comparable{ 2 String name; 3 int gpa; 4 @Ov

freemarker實現定義指令和定義函數

數據 dir variables macro 內置 引擎 eem fig turn 自定義指令: 1.指令在前臺實現   <#macro name param1,param2,param3...paramN>   </#macro> 2.指令在後臺實

實現定義查詢的數據庫設計及實現(一)

bre 名稱 審批流程 work 數據庫名 需要 自定義查詢 perm 枚舉 需求 先說一下需求:實現用戶自定義的查詢,用戶可以自定義要查詢的列、自定義條件條件、自定義排序。除了查詢使用外,還可以使用於各個需要根據條件進行約束的業務,如權限; 本設計和實現,很大部分是通過數

實現定義查詢的數據庫設計及實現(二)

表名 table abr bigint sts 處理 update 關聯表 creat 上部分大概講了一下表設計,這部分講一下處理。 處理的結構 處理結構的內容比較多,分為幾個部分分別講解一下。首先講解一下尋找關系表。 尋找關系表 尋找關系表根據“表間關系登記表”進行處

spring mvc實現定義註解

poi org param 運行時 onf dha ogg logs exec 實現方式:使用@Aspect實現: 1. 新建註解接口:CheckSign package com.soeasy.web.utils; import org.springframework.

ApiController實現定義身份認證

del api color span () log list() etc serialize 1 /// <summary> 2 /// 身份認證 3 /// </summary> 4 public class Au

利用echarts highcharts 實現定義地圖 關系圖效果 側邊3D柱形圖餅圖散點圖

技術 ges 散點圖 chart blog 餅圖 git 分享 charts github 地址: https://https://github.com/Gengshaoxuan/medataMap github 地址: https://https://github.c

關於Unity實現定義多邊形圖片效果

image 物體 length inspector 設置 this err eve mes 關於Unity實現自定義多邊形圖片效果 1.創建RawImageEditor編輯器拓展腳本(放在工程中Editor文件夾下,沒有則創建) 1 /*****************

python---redis實現定義session

ssm clas ges enc set hash blog dig 註意 SESSION_EXPIRE = 60 SESSION_TYPE = ‘Redis‘ pool = redis.ConnectionPool(host="localhost",port=6379)

thinkphp 5.0如何實現定義404(異常處理)頁面

錯誤頁 自定義異常 異常錯誤 錯誤 load php 錯誤信息 art 正常 404頁面是客戶端在瀏覽網頁時,由於服務器無法正常提供信息,或是服務器無法回應,且不知道原因所返回的頁面。404承載著用戶體驗與SEO優化的重任。404頁面通常為用戶訪問了網站上不存在或已刪除的

Android項目實戰(七):Dialog主題Activity實現定義對話框效果

utf 定義 nim 亮點 close .com 去除 span 代碼 原文:Android項目實戰(七):Dialog主題Activity實現自定義對話框效果想必大家都用過Dialog主題的Activity吧,用它來顯示自定義對話框效果絕對是一個非常不錯的選擇。 即把a

動態加載jar,實現定義業務

讀取 bool AR sta instance snapshot pub 加載 set 在實際業務中,我們經常會遇到需要按不同用戶實現不同業務邏輯,如果按照最簡單粗暴的做法,當然是使用if else ...來實現。 不過作為一個社會人,這樣怎麽能體現出我們的戰鬥力呢,下面