使用ffmpeg进行视频解码以及图像转换
2014-06-23 00:03
459 查看
http://blog.simophin.net/?p=816
ffmpeg作为一个支持非常多视频、音频格式的开源项目,其应用灰常广泛。今儿在这我们就探讨一下读者对其的理解,其中不泛错误谬误,望各位大大批评指教。这样做的原因主要是官方的文档比较匮乏。经过无数摸索,有一些经验分享。
1、Overview
ffmpeg里有几个重要的概念,熟悉它们以后,事情就变得简单多了。AVFormatContext代表一个打开的文件或者别的媒体,总之可以说代表数据的来源。视频和音频是按照一定格式存储在文件中的。这种格式仅仅指定如何把视频和音频流区分开来,至于视频如何变成图像,那是解码。平常所说的AVI格式,也就是上面所说的格式,里面视频、音频的编码方式还是可以随意的。
ffmpeg中的AVFormat库可以帮助进行这一“分拆音视频流”的过程;而AVCodec则帮助解码视频。
2、解码视频
(1)打开文件
1 2 3 4 5 6 7 8 9 10 | AVInputFormat *inputFmt; AVFormatContext *fmtCtx = NULL; inputFmt = av_find_input_format("avi"); /* 打开“AVI”的输入格式 */ if (inputFmt == NULL) { /* Error processing */ } if (av_open_input_file(&fmtCtx,"/test/test.avi", inputFmt, 0, NULL) != 0) { /* Error processing */ } |
(2)寻找解码器(视频)
1 2 3 4 5 6 7 8 9 1011 | int i, found_stream_index; AVCodecContext *videoDecodeCtx = NULL; for (i=0;i<fmtCtx->nb_streams;i++){ if (fmtCtx->streams[i]->codec->codec_type == AVMEDIA_VIDEO){ videoDecodeCtx = fmtCtx->streams[i]->codec; found_stream_index = i; break; } } if (decodeCtx == NULL) { /* 找不到视频流,错误处理 */ } |
以上代码中在文件所含的所有流中寻找视频流并得到一个解码器上下文。
(3)打开解码器
1 2 3 4 5 6 7 8 9 1011 | AVCodec *videoDecoder; videoDecoder = avcodec_find_encoder(videoDecodeCtx->codec_id); if (videoDecoder == NULL){ /* 找不到解码器,错误处理 */ } if (videoDecoder->capabilities & CODEC_CAP_TRUNCATED){ videoDecodeCtx->flags |= CODEC_FLAG_TRUNCATED; } if (avcodec_open(videoDecodeCtx,videoDecoder) < 0){ /* 打不开解码器,错误处理 */ } |
CODEC_CAP_TRUNCATED指明解码器可以支持所谓“碎片输入”,先不管它,等会儿再说。
如果都成功了,那么解码器就成功打开了。接下来就可以开始解码了。
(4)解码视频
1 2 3 4 5 6 7 8 9 1011 | AVPacket pkt; AVFrame *frame = avcodec_alloc_frame(); int got_picture = 0, rc = 0; while (1){ av_init_packet(&pkt); rc = av_read_packet(fmtCtx,&pkt); /* 获取一个包的数据 */ if (rc != 0) break; if (pkt.stream_index != found_stream_index) goto free_pkt_continue; /* 不是所关心的视频流的数据,舍去 */ if ( avcodec_decode_video2 (videoDecodeCtx, frame, &got_picture, &pkt) < 0) { /* 核心函数:解码。错误处理。 */ } if (got_picture) { { /* 处理获得的图像(存储在AVFrame里) */ } av_free(frame); frame = avcodec_alloc_frame(); } free_pkt_continue: av_free_packet(&pkt); } |
1. 读取数据;
2. 解码。
原始数据是以一个个AVPacket的形式存放的,而解出来的一帧图像存在AVFrame里。一帧图像可以由很多AVPacket组成,所以使用一个got_picture指针来指示是否获得一帧图像。
之前说的是关于CAP_TRUNCATED的问题,就是表明解码器是否支持AVFrame的边界和AVPacket的边界不重合。数据应该可以是零散的,解码器的这个能力很重要,它可以处理来自数据中的任一段(对于网络数据很有用)。
3、图像转换
这里说的图像转换,并非类似PNG到JPG的转换,而主要是色彩空间和大小伸缩的转换。例如MPEG4的解码器解出来的图像格式是YUV420P格式,而若让Qt来渲染图像,则需要RGB格式以及任意的大小。ffmpeg中提供swscale库来提供图像转换支持。现在假设我们在上一步解码出来的数据存放于AVFrame *frame中,我们有:
1 2 3 4 5 6 7 8 9 1011 | SwsContext *swsCtx; int dst_width = 320, /* 目标宽度 */ dst_height = 240, /* 目标高度 */ dst_pix_fmt = PIX_FMT_RGB24; /* 目标图像格式 */ AVFrame *convertedFrame = avcodec_alloc_frame(); swsCtx = sws_getContext ( videoDecodeCtx->width, videoDecodeCtx->height, videoDecodeCtx->pix_fmt, dst_width, dst_height, dst_pix_fmt, SWS_FAST_BILINEAR, NULL, NULL, NULL ); if (swsCtx == NULL) { /* 转换上下文初始化失败,错误处理 */ } /* 分配转换需要的内存 */ avpicture_fill ( (AVPicture *)convertedFrame,dst_pix_fmt, dst_width, dst_height); if (sws_scale(swsCtx,frame->data,frame->linesize,0, videoDecodeCtx->height,convertedFrame->data,convertedFrame->linesize) <= 0) { /* 转换失败,错误处理 */ } |
Rating: 9.1/10 (14 votes cast)
Rating: +5 (from 5 votes)
使用ffmpeg进行视频解码以及图像转换, 9.1 out
of 10 based on 14 ratings
已经发布的版本:
2011年1月7日 @ 23:53[当前修订版本] by 刘 凡超2011年1月7日
@ 23:41 by 刘 凡超
2011年1月7日
@ 23:41 by 刘 凡超
2011年1月7日
@ 23:20 by 刘 凡超
2011年1月7日
@ 23:02 by 刘 凡超
2011年1月7日
@ 23:02 by 刘 凡超
2011年1月7日
@ 23:01 by 刘 凡超
2011年1月7日
@ 23:01 by 刘 凡超
Be Sociable, Share!
相关文章推荐
- 使用ffmpeg进行视频解码以及图像转换
- 使用ffmpeg进行视频解码以及图像转换
- 使用ffmpeg进行视频解码以及图像转换
- 使用ffmpeg进行音视频编解码时用到的函数介绍
- 通过C++/CLI使用FFMPEG库进行视频解码[初步]
- Android音视频学习第2章:使用ffmpeg进行音频解码
- Android音视频学习第1章:使用ffmpeg进行视频解码
- 使用FFmpeg对视频进行编解码的一般流程
- 通过C++/CLI使用FFMPEG库进行视频解码[初步]
- 使用 ffmpeg 进行网络推流:拉流->解封装->解码->处理原始数据(音频、视频)->编码->编码->推流
- 使用FFMPEG3.4.2版本进行视频的解码为YUV格式
- 利用ffmpeg来进行视频解码的完整示例代码(H.264)
- 利用ffmpeg来进行视频解码的完整示例代码(H.264)
- php使用ffmpeg-php扩展库进行视频截图
- 利用ffmpeg来进行视频解码的完整示例代码(H.264)
- 在mvc3中使用ffmpeg对上传视频进行截图和转换格式
- php使用ffmpeg-php扩展库进行视频截图
- java 调用 ffmpeg 进行视频转换以及截图
- 在window下使用ffmpeg进行解码
- 使用FFMPEG对流数据进行解码