/******************
程序功能:
内存方式读取视频流,对视频流自定义分辨率进行播放
******************/
#include "sdl2\SDL.h"
extern "C"
{
#include "libavformat\avformat.h"
#include "libswscale\swscale.h"
};
FILE *fp = NULL;
int read_buffer(void *opaque,uint8_t *buf,int buf_size)
{
if(!feof(fp))
{
int true_size = fread(buf,1,buf_size,fp);
return true_size;
}
else
return -1;
}
/*
缩放一帧视频画面的分辨率(适用于YUV420P类型的视频帧):
pCodecCtx -- 保存了相应流的详细编码信息的结构体(如视频的宽、高、编码类型等)
pFrame -- 用于保存数据帧的数据结构(分辨率改变前)
pNewFrame -- 用于保存数据帧的数据结构(分辨率改变后)
NewWidth -- 新分辨率的宽度
NewHeight -- 新分辨率的高度
*/
void ResolutionChange(AVCodecContext *pCodecCtx,AVFrame *pFrame,AVFrame *pNewFrame,int pNewWidth,int pNewHeight)
{
pNewFrame->linesize[0] = pNewWidth;
pNewFrame->linesize[1] = pNewWidth/2;
pNewFrame->linesize[2] = pNewWidth/2;
//用 sws_getContext函数 得到 sws_scale函数 运行的上下文,之后用 sws_scale函数 将图形缩放
struct SwsContext *pSwsCtx = NULL;
pSwsCtx = sws_getContext(pCodecCtx->width,pCodecCtx->height,PIX_FMT_YUV420P,pNewWidth,pNewHeight,PIX_FMT_YUV420P,SWS_SINC,NULL,NULL,NULL);
if(pSwsCtx == NULL)
return ;
sws_scale(pSwsCtx,pFrame->data,pFrame->linesize,0,pCodecCtx->height,pNewFrame->data,pNewFrame->linesize);
sws_freeContext(pSwsCtx);
}
int main(int argc,char** argv)
{
av_register_all();
AVFormatContext *pFormatCtx = NULL;
pFormatCtx = avformat_alloc_context();
char filepath[]="test.flv";
fp = fopen(filepath,"rb");
if(fp == NULL)
exit(1);
unsigned char *aviobuffer = (unsigned char *)av_malloc(32768);//32K
AVIOContext *avio = avio_alloc_context(aviobuffer,32768,0,NULL,read_buffer,NULL,NULL);
pFormatCtx->pb = avio;
if(avformat_open_input(&pFormatCtx,NULL,NULL,NULL) != 0)
exit(1);
if(avformat_find_stream_info(pFormatCtx,NULL) < 0)
exit(1);
int videoIndex = -1;
for(int i=0;i<pFormatCtx->nb_streams;i++)
{
if(pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
{
videoIndex = i;
break;
}
}
if(videoIndex == -1)
exit(1);
AVCodecContext *pCodecCtx;
pCodecCtx = pFormatCtx->streams[videoIndex]->codec;
AVCodec *pCodec;
pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
if(pCodec == NULL)
exit(1);
if(avcodec_open2(pCodecCtx,pCodec,NULL) < 0)
exit(1);
AVFrame *pFrame,*pNewFrame;
pFrame = av_frame_alloc();
pNewFrame = av_frame_alloc();
if((pFrame == NULL) || (pNewFrame == NULL))
exit(1);
//自定义分辨率
int NewWidth = 640,NewHeight = 480;
int PictureSize = avpicture_get_size(PIX_FMT_YUV420P,NewWidth,NewHeight);
uint8_t* buffer = (uint8_t *)av_malloc(PictureSize*sizeof(uint8_t));
avpicture_fill((AVPicture *)pNewFrame,buffer,PIX_FMT_YUV420P,NewWidth,NewHeight);
if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO|SDL_INIT_TIMER))
exit(1);
SDL_Window *window = nullptr;
window = SDL_CreateWindow("MyPlayer",SDL_WINDOWPOS_UNDEFINED,SDL_WINDOWPOS_UNDEFINED,NewWidth,NewHeight,SDL_WINDOW_OPENGL);
if(!window)
exit(1);
SDL_Renderer *renderer = nullptr;
renderer = SDL_CreateRenderer(window,-1,0);
if(renderer == nullptr)
exit(1);
SDL_Texture *texture = nullptr;
texture = SDL_CreateTexture(renderer,SDL_PIXELFORMAT_YV12,SDL_TEXTUREACCESS_STREAMING,NewWidth,NewHeight);
SDL_Rect rect;
SDL_Event event;
AVPacket *packet=(AVPacket *)malloc(sizeof(AVPacket));
av_new_packet(packet,PictureSize);
int frameFinished;
while(av_read_frame(pFormatCtx,packet) >= 0)
{
if(packet->stream_index == videoIndex)
{
if(avcodec_decode_video2(pCodecCtx,pFrame,&frameFinished,packet) >= 0)
{
if(frameFinished)
{
ResolutionChange(pCodecCtx,pFrame,pNewFrame,NewWidth,NewHeight);
rect.x = 0;
rect.y = 0;
rect.w = NewWidth;
rect.h = NewHeight;
SDL_UpdateYUVTexture(texture,&rect,pNewFrame->data[0],pNewFrame->linesize[0],pNewFrame->data[1],pNewFrame->linesize[1],pNewFrame->data[2],pNewFrame->linesize[2]);
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer,texture,&rect,&rect);
SDL_RenderPresent(renderer);
SDL_Delay(20);
}
}
else
exit(1);
}
av_free_packet(packet);
SDL_PollEvent(&event);
switch(event.type)
{
case SDL_QUIT:
SDL_Quit();
exit(1);
break;
default:
break;
}
}
SDL_DestroyTexture(texture);
SDL_Quit();
av_free(buffer);
av_frame_free(&pNewFrame);
av_frame_free(&pFrame);
avcodec_close(pCodecCtx);
avformat_close_input(&pFormatCtx);
return 0;
}
FFmpeg_11_视频流自定义分辨率播放



FFmpeg 是一个强大的开源多媒体处理框架,用于处理音频和视频数据。在本项目"FFmpeg_11_视频流自定义分辨率播放"中,我们将深入探讨如何使用 FFmpeg 库来实现对视频流的自定义分辨率播放。这个过程通常涉及视频解码、分辨率转换和编码回放等关键步骤,主要针对 C++ 开发者。 我们需要理解 FFmpeg 的基本组件。FFmpeg 包含了 ffmpeg、ffplay、ffprobe 和 ffserver 四个主要工具,以及一系列的库,如 libavcodec(编解码器库)、libavformat(容器格式库)和 libavfilter(滤镜库)。在这个项目中,我们主要关注 libavformat 用于读取视频流,libavcodec 进行解码和编码,以及可能用到的 libavfilter 进行分辨率转换。 1. **视频流读取**:使用 `avformat_open_input` 函数打开视频文件,并通过 `avformat_find_stream_info` 获取流信息。这一步骤允许我们识别视频流中的不同轨道,包括视频、音频和其他元数据。 2. **解码视频流**:找到目标视频流后,利用 `avcodec_find_decoder` 获取相应的解码器,然后创建解码上下文 `avcodec_context` 并用 `avcodec_open2` 打开解码器。接着,使用 `avcodec_decode_video2` 函数逐帧解码视频数据。 3. **自定义分辨率转换**:在解码后的原始视频帧中,我们可以使用 FFmpeg 的过滤系统 `libavfilter` 来改变帧的分辨率。定义输入和输出过滤器上下文,创建一个分辨率转换过滤器(如 "scale"),并连接它们。之后,通过 `avfilter_init_dict` 初始化过滤器参数,如目标宽度和高度。使用 `avfilter_graph_config` 配置过滤器图,并用 `avfilter_copy_buffer_ref_props` 更新解码帧的属性。 4. **重新编码视频流**:如果需要,可以使用 `avcodec_find_encoder` 和 `avcodec_encode_video2` 对转换后的帧进行重新编码。这通常发生在输出到不同的格式或质量时。 5. **播放视频**:在 VC2010 环境下,可以利用 FFmpeg 的 `avpkt` 结构体和 `av_write_frame` 函数将编码后的帧写入输出文件。如果需要实时播放,可以构建一个简单的播放器,例如使用 `SDL` 或 `SFML` 图形库将编码帧显示到屏幕上。 6. **调试和编译**:项目中的 `FFmpeg.sdf` 和 `FFmpeg.sln` 文件是 Visual Studio 的解决方案文件和数据库文件,用于管理和构建项目。`Debug` 和 `ipch` 目录包含编译过程中的中间文件和预处理器缓存。 在实际应用中,开发者需要处理各种错误条件,如文件打开失败、解码错误、过滤器配置问题等,并确保代码的高效性和内存管理。同时,为了适应不同的硬件平台,可能还需要考虑性能优化和硬件加速支持。 "FFmpeg_11_视频流自定义分辨率播放"项目展示了如何利用 FFmpeg 库在 C++ 环境中实现对视频流的解码、分辨率转换和播放,这对于多媒体应用开发和视频处理具有很高的实用价值。通过实践这个项目,开发者可以更深入地理解和掌握 FFmpeg 的核心功能。





























































































































- 1
- 2
- 3

- #完美解决问题
- #运行顺畅
- #内容详尽
- #全网独家
- #注释完整
- xiaoyu112015-10-28可以用,有参考价值
- foxmoke2017-11-16感谢楼主的分享

- 粉丝: 30
- 资源: 111
我的内容管理 展开
我的资源 快来上传第一个资源
我的收益
登录查看自己的收益我的积分 登录查看自己的积分
我的C币 登录后查看C币余额
我的收藏
我的下载
下载帮助


最新资源
- 全文检索知识库档案管理系统kykms-DeepSeek资源
- (源码)基于Python的智能温室自动化系统.zip
- 健身协会活动小程序-活动资源
- (源码)基于Arduino平台的DMX通信和RDM协议处理项目.zip
- 健身协会活动小程序-活动资源
- KeyMouseHook-活动资源
- kis-flow-活动资源
- (源码)基于Arduino的CAN总线通讯与状态检测系统.zip
- LetsOJ_多人刷题打卡-C语言资源
- (源码)基于 JavaScript 的 larkplayerhls 视频播放插件.zip
- (源码)基于Arduino的电子墨水屏图书展示系统.zip
- xmake-C++资源
- kisso-Java资源
- JFinal-Python资源
- (源码)基于Arduino的雪茄柜温湿度监控系统.zip
- SwiftSQLiteORM-Swift资源


