把jpeg圖片轉換爲任意視頻格式

在一些嵌入式系統中,視頻以jpeg圖像格式傳出來,並且數據量很是大。這種狀況下若是要對jpeg圖像進行解碼而且從新編碼成264之類的格式再 放入視頻容器中會消耗大量的CPU資源,若不是性能特別犀利的CPU是沒法承受的,這個時候有一個折衷的辦法,就是直接將jpeg連續保存起來(也就是保 存成mjpeg視頻格式),而後直接放入視頻容器中。html

這個方面的代碼實現網上資料比較少,能夠說幾乎沒有,基本都是直接用FFmpeg的命令行來實現的,這一方法雖然可行但畢竟不太適合軟件的集成,是故本人作了些研究,並將代碼放出來供各位參考指正。數據結構

在貼出代碼以前特別感謝雷霄驊老師的博客,其關於FFmpeg的博文提供了很是多的參考,若是對FFmpeg有深刻了解需求的能夠去看看,會有不少收穫。函數

下面上代碼:性能

環境爲:VS2013 C++ 控制檯程序(空項目)+ FFmpeg(配置相關可參考本人以前博文)編碼

 

view sourceprint?spa

001.#include <stdio.h>.net

002. 命令行

003.extern "C"//包含C文件頭code

004.{orm

005.#include "libavformat/avformat.h"

006.};

007.#define DATASIZE 1024*1024

008. 

009.AVStream *add_vidio_stream(AVFormatContext *oc, enum AVCodecID codec_id)//用以初始化一個用於輸出的AVFormatContext結構體

010.{

011.AVStream *st;

012.AVCodec *codec;

013. 

014.st = avformat_new_stream(oc, NULL);

015.if (!st)

016.{

017.printf("Could not alloc stream

018.");

019.exit(1);

020.}

021.codec = avcodec_find_encoder(codec_id);//查找mjpeg解碼器

022.if (!codec)

023.{

024.printf("codec not found

025.");

026.exit(1);

027.}

028.avcodec_get_context_defaults3(st->codec, codec);//申請AVStream->codec(AVCodecContext對象)空間並設置默認值(由avcodec_get_context_defaults3()設置

029. 

030.st->codec->bit_rate = 400000;//設置採樣參數,即比特率 

031.st->codec->width = 1080;//設置視頻寬高,這裏跟圖片的寬高保存一致便可

032.st->codec->height = 1800;

033.st->codec->time_base.den = 10;//設置幀率

034.st->codec->time_base.num = 1;

035. 

036.st->codec->pix_fmt = PIX_FMT_YUV420P;//設置像素格式 

037.st->codec->codec_tag = 0;

038.if (oc->oformat->flags & AVFMT_GLOBALHEADER)//一些格式須要視頻流數據頭分開

039.st->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;

040.return st;

041.}

042. 

043.void main()

044.{

045.AVFormatContext *ofmt_ctx = NULL;//其包含碼流參數較多,是一個貫穿始終的數據結構,不少函數都要用到它做爲參數

046.const char *out_filename = "out.mkv";//輸出文件路徑,在這裏也能夠將mkv改爲別的ffmpeg支持的格式,如mp4,flv,avi之類的

047.int ret;//返回標誌

048. 

049.av_register_all();//初始化解碼器和複用器

050.avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, out_filename);//初始化一個用於輸出的AVFormatContext結構體,視頻幀率和寬高在此函數裏面設置

051.if (!ofmt_ctx)

052.{

053.printf("Could not create output context

054.");

055.return;

056.}

057. 

058.AVStream *out_stream = add_vidio_stream(ofmt_ctx, AV_CODEC_ID_MJPEG);//創造輸出視頻流

059.av_dump_format(ofmt_ctx, 0, out_filename, 1);//該函數會打印出視頻流的信息,若是看着不開心能夠不要

060. 

061.if (!(ofmt_ctx->oformat->flags & AVFMT_NOFILE))//打開輸出視頻文件

062.{

063.ret = avio_open(&ofmt_ctx->pb, out_filename, AVIO_FLAG_WRITE);

064.if (ret < 0) {

065.printf("Could not open output file '%s'", out_filename);

066.return;

067.}

068.}

069. 

070.if (avformat_write_header(ofmt_ctx, NULL) < 0)//寫文件頭(Write file header)

071.{

072.printf("Error occurred when opening output file

073.");

074.return;

075.}

076. 

077.int frame_index = 0;//放入視頻的圖像計數

078.unsigned char *mydata = new unsigned char[DATASIZE];

079.AVPacket pkt;

080.av_init_packet(&pkt);

081.pkt.flags |= AV_PKT_FLAG_KEY;

082.pkt.stream_index = out_stream->index;//獲取視頻信息,爲壓入幀圖像作準備

083.while (frame_index<100)//將圖像壓入視頻中

084.{

085.FILE *file;//打開一張jpeg圖像並讀取其數據,在這裏圖像最大爲1M,若是超過1M,則須要修改1024*1024這裏

086.fopen_s(&file, "1.jpg", "rb");

087.pkt.size = fread(mydata, 1, DATASIZE, file);

088.pkt.data = mydata;

089.fclose(file);

090.if (av_interleaved_write_frame(ofmt_ctx, &pkt) < 0) //寫入圖像到視頻

091.{

092.printf("Error muxing packet

093.");

094.break;

095.}

096.printf("Write %8d frames to output file

097.", frame_index);//打印出當前壓入的幀數

098.frame_index++;

099.}

100.av_free_packet(&pkt);//釋放掉幀數據包對象

101.av_write_trailer(ofmt_ctx);//寫文件尾(Write file trailer)

102.delete[]mydata;//釋放數據對象

103.if (ofmt_ctx && !(ofmt_ctx->oformat->flags & AVFMT_NOFILE))

104.avio_close(ofmt_ctx->pb);//關閉視頻文件

105.avformat_free_context(ofmt_ctx);//釋放輸出視頻相關數據結構

106.return;

107.}

相關文章
相關標籤/搜索