演示基于SDL2.0+FFmpeg的播放器
SDL是一个跨平台的渲染组件,眼下已经推出到2.0.3版本号,支持Win/Linux/OSX/Android。网上非常多介绍大多是基于SDL1.2版本号的,与2.0版本号有一定的区别,本文演示怎样用SDL2.0版本号播放视频(仅视频)。
SDL下载站点:http://libsdl.org
參考网址:http://blog.csdn.net/dawdo222/article/details/8692834
上代码:
// 演示怎样用SDL2进行播放
//可參考http://blog.csdn.net/dawdo222/article/details/8692834 #include "stdafx.h"
#include <stdio.h>
#include <tchar.h>
#include <io.h>
#include <direct.h>
#include <windows.h> extern "C"
{
// ffmpeg
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
// SDL
#include "SDL203include/SDL.h"
#include "SDL203include/SDL_thread.h"
}; #pragma comment(lib,"../lib/avutil.lib")
#pragma comment(lib,"../lib/avcodec.lib")
#pragma comment(lib,"../lib/avformat.lib")
#pragma comment(lib,"../lib/swscale.lib")
#pragma comment(lib,"../lib/sdl2.lib") //把參数转换为utf8
void prepare_app_arguments2(int *argc_ptr, char ***argv_ptr)
{
int i, nSize, newSize, buffsize;
char *argv;
char **argv2;
wchar_t* lpWideCharStr;
char* buf;
char** win32_argv_utf8 = NULL;
argv2 = *argv_ptr; buffsize = 0;
/* determine the UTF-8 buffer size (including NULL-termination symbols) */
for (i = 0; i < *argc_ptr; i++)
{
argv = argv2[i];
nSize = MultiByteToWideChar(CP_ACP, 0, argv, strlen(argv)*sizeof(char), NULL, 0);
lpWideCharStr = (wchar_t*)av_mallocz( (nSize+1) * sizeof(wchar_t));
MultiByteToWideChar(CP_ACP, 0, argv, strlen(argv)*sizeof(wchar_t), lpWideCharStr, nSize);
buffsize += WideCharToMultiByte(CP_UTF8, 0, lpWideCharStr, -1, NULL, 0, NULL, NULL);
av_free(lpWideCharStr);
} win32_argv_utf8 = (char**)av_mallocz(sizeof(char *) * (*argc_ptr + 1) + buffsize); for (i = 0; i < *argc_ptr; i++)
{
argv = argv2[i];
nSize = MultiByteToWideChar(CP_ACP, 0, argv, strlen(argv)*sizeof(char), NULL, 0);
lpWideCharStr = (wchar_t*)av_mallocz( (nSize+1) * sizeof(wchar_t));
memset(lpWideCharStr, 0, (nSize+1)*sizeof(wchar_t));
nSize = MultiByteToWideChar(CP_ACP, 0, argv, strlen(argv)*sizeof(wchar_t), lpWideCharStr, nSize);
nSize =WideCharToMultiByte(CP_UTF8 ,0,lpWideCharStr,-1,NULL,0,NULL,NULL);
buf = (char*)av_mallocz( (nSize+1) * sizeof(char));//new char[nSize+1];
memset(buf, 0, nSize+1);
newSize = WideCharToMultiByte(CP_UTF8 ,0,lpWideCharStr,-1,buf,nSize,NULL,NULL);
av_free(lpWideCharStr);
win32_argv_utf8[i] = buf;
}
*argc_ptr = *argc_ptr;
*argv_ptr = win32_argv_utf8;
} int _tmain(int argc, char* argv[])
{
///////////////////////////////////////////////////////////////////////////////
// ffmpeg
// Register all formats and codecs
av_register_all(); // Open video file
AVFormatContext *pFormatCtx = NULL;
prepare_app_arguments2(&argc, &argv);//转成UTF-8
const char* filename = "d:\\clip\\avander2.mp4";//argv[1];
if( avformat_open_input(&pFormatCtx, filename, NULL, NULL) != 0 ) {
return -1; // Couldn't open file
} // Retrieve stream information
if( avformat_find_stream_info(pFormatCtx, NULL) < 0 ) {
return -1; // Couldn't find stream information
} // Dump information about file onto standard error
av_dump_format(pFormatCtx, 0, filename, 0);
// Find the first video stream
int videoStream = -1;
for(int i=0; i < pFormatCtx->nb_streams; i++) {
if( pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO ) {
videoStream = i;
break;
}
}
if( videoStream == -1) {
return -1; // Didn't find a video stream
} // Get a pointer to the codec context for the video stream
AVCodecContext * pCodecCtx = pFormatCtx->streams[videoStream]->codec; // Find the decoder for the video stream
AVCodec* pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
if( pCodec == NULL ) {
fprintf(stderr, "Unsupported codec!\n");
return -1; // Codec not found
} // Open codec
AVDictionary* optionsDict = NULL;
if( avcodec_open2(pCodecCtx, pCodec, &optionsDict) < 0 ) {
return -1; // Could not open codec
}
//源颜色格式
AVPixelFormat src_fix_fmt = pCodecCtx->pix_fmt; //AV_PIX_FMT_YUV420P
//目标颜色格式
AVPixelFormat dst_fix_fmt = PIX_FMT_BGR24;//PIX_FMT_YUV420P
// Allocate video frame
AVFrame* pFrame = av_frame_alloc();
AVFrame* pFrameYUV = av_frame_alloc();
if( pFrameYUV == NULL ) {
return -1;
} struct SwsContext* sws_ctx = sws_getContext(
pCodecCtx->width,
pCodecCtx->height,
pCodecCtx->pix_fmt,
pCodecCtx->width,
pCodecCtx->height,
dst_fix_fmt,//PIX_FMT_BGR24,//PIX_FMT_YUV420P,
SWS_BILINEAR,
NULL,
NULL,
NULL); int numBytes = avpicture_get_size(
dst_fix_fmt,//PIX_FMT_YUV420P,
pCodecCtx->width,
pCodecCtx->height);
uint8_t* buffer = (uint8_t *)av_malloc( numBytes*sizeof(uint8_t) ); avpicture_fill((AVPicture *)pFrameYUV, buffer, dst_fix_fmt,//PIX_FMT_YUV420P,
pCodecCtx->width, pCodecCtx->height); // Read frames and save first five frames to disk
SDL_Rect sdlRect;
sdlRect.x = 0;
sdlRect.y = 0;
sdlRect.w = pCodecCtx->width;
sdlRect.h = pCodecCtx->height; //////////////////////////////////////////////////////
// SDL
if( SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER )) {
fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError());
exit(1);
} SDL_Window* sdlWindow = SDL_CreateWindow("My Game Window",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
pCodecCtx->width, pCodecCtx->height,
0);
if( !sdlWindow ) {
fprintf(stderr, "SDL: could not set video mode - exiting\n");
exit(1);
} SDL_Renderer* sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, SDL_RENDERER_TARGETTEXTURE); //原本第三个參数是0
SDL_Texture* sdlTexture = SDL_CreateTexture(
sdlRenderer,
SDL_PIXELFORMAT_BGR24,//SDL_PIXELFORMAT_YV12,
SDL_TEXTUREACCESS_STATIC,//SDL_TEXTUREACCESS_STREAMING,
pCodecCtx->width,
pCodecCtx->height);
if(!sdlTexture)
return -1;
SDL_SetTextureBlendMode(sdlTexture,SDL_BLENDMODE_BLEND ); AVPacket packet;
SDL_Event event;
while( av_read_frame(pFormatCtx, &packet) >= 0 ) {
// Is this a packet from the video stream?
if( packet.stream_index == videoStream ) {
// Decode video frame
int frameFinished;
avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet); // Did we get a video frame?
if( frameFinished ) {
sws_scale(
sws_ctx,
(uint8_t const * const *)pFrame->data,
pFrame->linesize,
0,
pCodecCtx->height,
pFrameYUV->data,
pFrameYUV->linesize
); SDL_UpdateTexture( sdlTexture, &sdlRect, pFrameYUV->data[0], pFrameYUV->linesize[0] );
SDL_RenderClear( sdlRenderer );
SDL_RenderCopy( sdlRenderer, sdlTexture, &sdlRect, &sdlRect );
SDL_RenderPresent( sdlRenderer );
}
SDL_Delay(50);
} // Free the packet that was allocated by av_read_frame
av_free_packet(&packet);
SDL_PollEvent(&event);
switch( event.type ) {
case SDL_QUIT:
SDL_Quit();
exit(0);
break;
default:
break;
} } SDL_DestroyTexture(sdlTexture); // Free the YUV frame
av_free(pFrame);
av_free(pFrameYUV); // Close the codec
avcodec_close(pCodecCtx); // Close the video file
avformat_close_input(&pFormatCtx); return 0;
}
上述代码演示了怎样把视频帧转换为BGR24格式,然后用SDL的纹理函数渲染到屏幕上。
不完好的地方:没有音频部分,更没有视音频同步,播放帧率固定设为20帧/秒。
演示基于SDL2.0+FFmpeg的播放器的更多相关文章
- 基于ffmpeg网络播放器的教程与总结
基于ffmpeg网络播放器的教程与总结 一. 概述 为了解决在线无广告播放youku网上的视频.(youku把每个视频切换成若干个小视频). 视频资源解析可以从www.flvcd. ...
- FFmpeg简易播放器的实现-视频播放
本文为作者原创:https://www.cnblogs.com/leisure_chn/p/10047035.html,转载请注明出处 基于FFmpeg和SDL实现的简易视频播放器,主要分为读取视频文 ...
- FFmpeg简易播放器的实现-音视频播放
本文为作者原创,转载请注明出处:https://www.cnblogs.com/leisure_chn/p/10235926.html 基于FFmpeg和SDL实现的简易视频播放器,主要分为读取视频文 ...
- FFmpeg简易播放器的实现-音频播放
本文为作者原创,转载请注明出处:https://www.cnblogs.com/leisure_chn/p/10068490.html 基于FFmpeg和SDL实现的简易视频播放器,主要分为读取视频文 ...
- FFmpeg简易播放器的实现-最简版
本文为作者原创:https://www.cnblogs.com/leisure_chn/p/10040202.html,转载请注明出处 基于FFmpeg和SDL实现的简易视频播放器,主要分为读取视频文 ...
- FFmpeg简易播放器的实现-音视频同步
本文为作者原创,转载请注明出处:https://www.cnblogs.com/leisure_chn/p/10284653.html 基于FFmpeg和SDL实现的简易视频播放器,主要分为读取视频文 ...
- 基于jQuery仿QQ音乐播放器网页版代码
基于jQuery仿QQ音乐播放器网页版代码是一款黑色样式风格的网页QQ音乐播放器样式代码.效果图如下: 在线预览 源码下载 实现的代码. html代码: <div class="m ...
- iOS之基于FreeStreamer的简单音乐播放器(模仿QQ音乐)
代码地址如下:http://www.demodashi.com/demo/11944.html 天道酬勤 前言 作为一名iOS开发者,每当使用APP的时候,总难免会情不自禁的去想想,这个怎么做的?该怎 ...
- 基于MFC的Media Player播放器的制作(3---功能实现)
| 版权声明:本文为博主原创文章,未经博主允许不得转载. 下面我们试试一下,按下退出Button退出播放器的功能: 首先,我们双击退出Button按钮,就会弹出下图的框: 上面的弄好之后我们就实现 ...
随机推荐
- [置顶] Bug 11775332 - cluvfy fails with PRVF-5636 with DNS response timeout error [ID 11775332.8]
Bug 11775332 cluvfy fails with PRVF-5636 withDNS response timeout error but error text is not clear ...
- Delphi VMT的前世今生(研究一下D7的VMT表结构)
主要是TObject那些虚函数,到底放在了哪里?
- 深刻:截获windows的消息并分析实例(DefWindowProc),以WM_NCHITTEST举例(Windows下每一个鼠标消息都是由 WM_NCHITTEST 消息产生的,这个消息的参数包含了鼠标位置的信息)
1,回调函数工作机制 回调函数由操作系统自动调用,回调函数的返回值当然也是返回给操作系统了. 2,截获操作系统发出的消息,截获到后,将另外一个消息返回给操作系统,已达到欺骗操作系统的目的. 下面还是以 ...
- [SVN]两个分支合并
Date:2014-1-1 Summary: 记录一下自己使用SVN时候的操作步骤,先吃鱼,再学钓鱼 Contents: 环境:从同事的branch迁出一份代码,作为自己的分支进行开发,同时同事也在自 ...
- Zero Clipboard - 跨浏览器兼容的“复制到剪贴板”功能
开发中经常会用到复制的功能,在 IE 下实现比较简单,但要想做到跨浏览器比较困难了. 本文将介绍一个跨浏览器的库类 Zero Clipboard ,它利用 Flash 进行复制,所以只要浏览器装有 F ...
- Android Studio Gradle 添加.so 支持文件
近期发展Android Wear 关注商品.官员Demo所有gradle 工程. 当然,我也用eclipse配置一个可行的环境. 问题来了,eclipse,android studio 开发 andr ...
- ORACLE:plsql优化
1.登录后默认自动选中My Objects? 设置方法:Tools菜单--Brower Filters会打开Brower Filters的定单窗口,把“My Objects”设为默认即可.? 同理 ...
- Spring中继承配置的注入方法
(1)两个java类.一个父类一个字类 package com.lc.inherit; /* * 这里是父类 */ public class Student { protected String na ...
- cocos2d-x3.2下使用Umeng 64位SDK注意事项
友盟官方的样例中已经有了Cocos2d-x的Demo使用起来也是比較方便的.但在64位的版本号使用时须要注意 32位SDK改动: 将Xcode中Build Settings的Architectures ...
- Android_app项目开发步骤总结
做了几个android企业应用项目后,总结了项目的基本开发步骤.希望可以交流. 一 应用规划: ※确定功能. ※必须的界面及界面跳转的流程. ※须要的数据及数据的来源及格 ...