在一些嵌入式系統中,視頻以jpeg圖像格式傳出來,並且數據量很是大。這種狀況下若是要對jpeg圖像進行解碼而且從新編碼成264之類的格式再 放入視頻容器中會消耗大量的CPU資源,若不是性能特別犀利的CPU是沒法承受的,這個時候有一個折衷的辦法,就是直接將jpeg連續保存起來(也就是保 存成mjpeg視頻格式),而後直接放入視頻容器中。html
這個方面的代碼實現網上資料比較少,能夠說幾乎沒有,基本都是直接用FFmpeg的命令行來實現的,這一方法雖然可行但畢竟不太適合軟件的集成,是故本人作了些研究,並將代碼放出來供各位參考指正。數據結構
在貼出代碼以前特別感謝雷霄驊老師的博客,其關於FFmpeg的博文提供了很是多的參考,若是對FFmpeg有深刻了解需求的能夠去看看,會有不少收穫。函數
下面上代碼:性能
環境爲:VS2013 C++ 控制檯程序(空項目)+ FFmpeg(配置相關可參考本人以前博文)編碼
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.
}