FFMPEG 视频图像解封装解码
FFMPEG4.0 音頻解碼解封裝
FFMPEG 音頻封裝編碼
下面的函數(shù)方法基于最新的FFMPEG 4.0(4.X):
本文講是如何從一個(gè)視頻文件中提取出其中的圖像數(shù)據(jù),并將圖像數(shù)據(jù)保存到文件中。
解碼解封裝的過(guò)程與音頻差不多,具體如下:
1.讀取視頻文件的格式信息
2.獲取視頻流
int st_index = av_find_best_stream(fmt_ctx,AVMEDIA_TYPE_VIDEO,-1,-1,NULL,0);LOGV("st_index = %d\n",st_index);AVStream *st = fmt_ctx->streams[st_index];3.準(zhǔn)備×××與解碼context
AVCodec *codec = avcodec_find_decoder(st->codecpar->codec_id);AVCodecContext *codec_ctx = avcodec_alloc_context3(codec);4.拷貝視頻流中的參數(shù)到×××context中并打開(kāi)×××
avcodec_parameters_to_context(codec_ctx,st->codecpar);avcodec_open2(codec_ctx,codec,NULL);5.讀取視頻的格式、寬高信息
int width = codec_ctx->width;int height = codec_ctx->height;enum AVPixelFormat pixel_fmt = codec_ctx->pix_fmt;6.申請(qǐng)圖像存儲(chǔ)空間
uint8_t *dst_buf[4] = {0};int dst_linesize[4];int size = av_image_alloc(dst_buf,dst_linesize,width,height,pixel_fmt,1);7.申明存儲(chǔ)原始數(shù)據(jù)與解碼后數(shù)據(jù)的packet與frame
AVFrame *frame = av_frame_alloc();AVPacket *packet = av_packet_alloc();8.讀取數(shù)據(jù),只取用視頻數(shù)據(jù)
int ret = av_read_frame(fmt_ctx,packet); //讀取到的packet不僅僅是圖像數(shù)據(jù),還有音頻、字幕等數(shù)據(jù)。 if(packet->stream_index != st_index) {continue; }9.發(fā)送數(shù)據(jù)進(jìn)行解碼
ret = avcodec_send_packet(codec_ctx,packet);
10.接收解碼后的原始數(shù)據(jù),這是個(gè)反復(fù)的過(guò)程,一個(gè)packet可能解碼出好幾個(gè)frame
注意:收到的frame可能存在寬高或者fmt格式變化這種情況,后面的流程代碼沒(méi)有考慮這種情況(這種奇葩視頻應(yīng)該不會(huì)遇到)
if(frame->width != width || frame->height != height || frame->format != pixel_fmt){LOGV("eeeeeeeeeeeee");}11.把frame中的數(shù)據(jù)拷貝到事先準(zhǔn)備的dst_buf中。二維指針數(shù)組看作一位數(shù)組。
av_image_copy(dst_buf,dst_linesize,frame->data,frame->linesize,pixel_fmt,width,height);
12.把數(shù)據(jù)寫(xiě)入文件。
fwrite(dst_buf[0],1,size,out_file);
下面貼一段完整的示例代碼,代碼沒(méi)有考慮失敗的情況,結(jié)尾沒(méi)有搞釋放,也沒(méi)有flush×××,示例只是為了掌握整個(gè)核心解碼流程。
/** demuxing_decode_video.c** Created on: 2019年1月8日* Author: deanliu*/#include <libavutil/imgutils.h> #include <libavutil/samplefmt.h> #include <libavutil/timestamp.h> #include <libavformat/avformat.h>static char log_buf[1024*8]; #define LOGV(...) av_log(NULL,AV_LOG_VERBOSE,__VA_ARGS__)void ffmpeg_log_callback(void* ptr, int level, const char* fmt, va_list vl) {static int print_prefix = 1;av_log_format_line(ptr,level,fmt,vl,log_buf,sizeof(log_buf),&print_prefix);fprintf(stderr,"%s",log_buf); }int main() {av_log_set_callback(ffmpeg_log_callback);char *input = "E:/測(cè)試音視頻/12種格式視頻/test.avi";char *output = "d:/video.v";FILE *out_file = fopen(output,"wb");AVFormatContext *fmt_ctx;fmt_ctx = avformat_alloc_context();avformat_open_input(&fmt_ctx,input,NULL,NULL);avformat_find_stream_info(fmt_ctx,NULL);int st_index = av_find_best_stream(fmt_ctx,AVMEDIA_TYPE_VIDEO,-1,-1,NULL,0);LOGV("st_index = %d\n",st_index);AVStream *st = fmt_ctx->streams[st_index];AVCodec *codec = avcodec_find_decoder(st->codecpar->codec_id);AVCodecContext *codec_ctx = avcodec_alloc_context3(codec);avcodec_parameters_to_context(codec_ctx,st->codecpar);avcodec_open2(codec_ctx,codec,NULL);int width = codec_ctx->width;int height = codec_ctx->height;enum AVPixelFormat pixel_fmt = codec_ctx->pix_fmt;uint8_t *dst_buf[4] = {0};int dst_linesize[4];int size = av_image_alloc(dst_buf,dst_linesize,width,height,pixel_fmt,1);AVFrame *frame = av_frame_alloc();AVPacket *packet = av_packet_alloc();while(1){LOGV("READ\n");int ret = av_read_frame(fmt_ctx,packet);if(ret < 0){LOGV("ret = %d\n",ret);break;}if(packet->stream_index != st_index){continue;}LOGV("SENT\n");ret = avcodec_send_packet(codec_ctx,packet);if(ret < 0){return 1;}while(ret >= 0){LOGV("receiver\n");ret = avcodec_receive_frame(codec_ctx,frame);if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)break;if(ret < 0) {return 1;}if(frame->width != width || frame->height != height || frame->format != pixel_fmt){LOGV("eeeeeeeeeeeee");}av_image_copy(dst_buf,dst_linesize,frame->data,frame->linesize,pixel_fmt,width,height);LOGV("dst_buf = %d,%d,%d,%d\n",dst_buf[2][0],dst_buf[1][1],dst_buf[0][2],dst_buf[0][3]);fwrite(dst_buf[0],1,size,out_file);}}LOGV("dst_linesize = %d,%d,%d,%d\n",dst_linesize[0],dst_linesize[1],dst_linesize[2],size);printf("Play the output video file with the command:\n""ffplay -f rawvideo -pix_fmt %s -video_size %dx%d %s\n",av_get_pix_fmt_name(pixel_fmt), width, height,output);LOGV("END!!");fclose(out_file);return 0; }轉(zhuǎn)載于:https://blog.51cto.com/4095821/2402711
總結(jié)
以上是生活随笔為你收集整理的FFMPEG 视频图像解封装解码的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: vb.net使用DirectX入门知识
- 下一篇: 梯度下降法和随机梯度下降法