## An ffmpeg and SDL Tutorial
Page 1 2 3 4 5 6 7 End Prev Home Next  _place_holder;
Text version
## Tutorial 04: Spawning Threads
Code: tutorial04.c
### Overview
Last time we added audio support by taking advantage of SDL's audio functions.
SDL started a thread that made callbacks to a function we defined every time
it needed audio. Now we're going to do the same sort of thing with the video
display. This makes the code more modular and easier to work with - especially
when we want to add syncing. So where do we start?
First we notice that our main function is handling an awful lot: it's running
through the event loop, reading in packets, and decoding the video. So what
we're going to do is split all those apart: we're going to have a thread that
will be responsible for decoding the packets; these packets will then be added
to the queue and read by the corresponding audio and video threads. The audio
thread we have already set up the way we want it; the video thread will be a
little more complicated since we have to display the video ourselves. We will
add the actual display code to the main loop. But instead of just displaying
video every time we loop, we will integrate the video display into the event
loop. The idea is to decode the video, save the resulting frame in _another_
queue, then create a custom event (`FF_REFRESH_EVENT`) that we add to the
event system, then when our event loop sees this event, it will display the
next frame in the queue. Here's a handy ASCII art illustration of what is
going on:
________ audio _______ _____
| | pkts | | | | to spkr
| DECODE |----->| AUDIO |--->| SDL |-->
|________| |_______| |_____|
| video _______
| pkts | |
+---------->| VIDEO |
________ |_______| _______
| | | | |
| EVENT | +------>| VIDEO | to mon.
| LOOP |----------------->| DISP. |-->
|_______|<---FF_REFRESH----|_______|
The main purpose of moving controlling the video display via the event loop is
that using an SDL_Delay thread, we can control exactly when the next video
frame shows up on the screen. When we finally sync the video in the next
tutorial, it will be a simple matter to add the code that will schedule the
next video refresh so the right picture is being shown on the screen at the
right time.
### Simplifying Code
We're also going to clean up the code a bit. We have all this audio and video
codec information, and we're going to be adding queues and buffers and who
knows what else. All this stuff is for one logical unit, _viz._ the movie. So
we're going to make a large struct that will hold all that information called
the `VideoState`.
typedef struct VideoState {
AVFormatContext *pFormatCtx;
int videoStream, audioStream;
AVStream *audio_st;
AVCodecContext *audio_ctx;
PacketQueue audioq;
uint8_t audio_buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2];
unsigned int audio_buf_size;
unsigned int audio_buf_index;
AVPacket audio_pkt;
uint8_t *audio_pkt_data;
int audio_pkt_size;
AVStream *video_st;
AVCodecContext *video_ctx;
PacketQueue videoq;
VideoPicture pictq[VIDEO_PICTURE_QUEUE_SIZE];
int pictq_size, pictq_rindex, pictq_windex;
SDL_mutex *pictq_mutex;
SDL_cond *pictq_cond;
SDL_Thread *parse_tid;
SDL_Thread *video_tid;
char filename[1024];
int quit;
} VideoState;
Here we see a glimpse of what we're going to get to. First we see the basic
information - the format context and the indices of the audio and video
stream, and the corresponding AVStream objects. Then we can see that we've
moved some of those audio buffers into this structure. These (audio_buf,
audio_buf_size, etc.) were all for information about audio that was still
lying around (or the lack thereof). We've added another queue for the video,
and a buffer (which will be used as a queue; we don't need any fancy queueing
stuff for this) for the decoded frames (saved as an overlay). The VideoPicture
struct is of our own creations (we'll see what's in it when we come to it). We
also notice that we've allocated pointers for the two extra threads we will
create, and the quit flag and the filename of the movie.
So now we take it all the way back to the main function to see how this
changes our program. Let's set up our `VideoState` struct:
int main(int argc, char *argv[]) {
SDL_Event event;
VideoState *is;
is = av_mallocz(sizeof(VideoState));
`av_mallocz()` is a nice function that will allocate memory for us and zero it
out.
Then we'll initialize our locks for the display buffer (`pictq`), because
since the event loop calls our display function - the display function,
remember, will be pulling pre-decoded frames from `pictq`. At the same time,
our video decoder will be putting information into it - we don't know who will
get there first. Hopefully you recognize that this is a classic **race
condition**. So we allocate it now before we start any threads. Let's also
copy the filename of our movie into our `VideoState`.
av_strlcpy(is->filename, argv[1], sizeof(is->filename));
is->pictq_mutex = SDL_CreateMutex();
is->pictq_cond = SDL_CreateCond();
`av_strlcpy` is a function from ffmpeg that does some extra bounds checking
beyond strncpy.
### Our First Thread
Now let's finally launch our threads and get the real work done:
schedule_refresh(is, 40);
is->parse_tid = SDL_CreateThread(decode_thread, is);
if(!is->parse_tid) {
av_free(is);
return -1;
}
`schedule_refresh` is a function we will define later. What it basically does
is tell the system to push a `FF_REFRESH_EVENT` after the specified number of
milliseconds. This will in turn call the video refresh function when we see it
in the event queue. But for now, let's look at `SDL_CreateThread()`.
`SDL_CreateThread()` does just that - it spawns a new thread that has complete
access to all the memory of the original process, and starts the thread
running on the function we give it. It will also pass that function user-
defined data. In this case, we're calling `decode_thread()` and with our
`VideoState` struct attached. The first half of the function has nothing new;
it simply does the work of opening the file and finding the index of the audio
and video streams. The only thing we do different is save the format context
in our big struct. After we've found our stream indices, we call another
function that we will define, `stream_component_open()`. This is a pretty
natural way to split things up, and since we do a lot of similar things to set
up the video and audio codec, we reuse some code by making this a function.
The `stream_component_open()` function is where we will find our codec
decoder, set up our audio options, save important information to our big
struct, and launch our audio and video threads. This is where we would also
insert other options, such as forcing the codec instead of autodetecting it
and so forth. Here it is:
int stream_component_open(VideoState *is, int stream_index) {
AVFormatContext *pFormatCtx = is->pFormatCtx;
AVCodecContext *codecCtx;
AVCodec *codec;
SDL_AudioSpec wanted_spec, spec;
if(stream_index < 0 || stream_index >= pFormatCtx->nb_streams) {
return -1;
}
codec = avcodec_find_decoder(pFormatCtx->streams[stream_index]->codec->codec_id);
if(!codec) {
fprintf(stderr, "Unsupported codec!\n");
return -1;
}
codecCtx = avcodec_alloc_context3(codec);
if(avcode
没有合适的资源?快使用搜索试试~ 我知道了~
温馨提示
vs2013 ffmpeg2.8 SDL1.2的同步播放器,对学习如何写简单的播放器初学者有用。tutorial04.c修正了用SDL2.0,其他的用的是SDL1.2。自己可以根据tutorial04.c对相应的工程修改用SDL2.0。tutorial06.c。修改了同步到外部时钟视频的起始时间不是从0开始的情况。tutorial07.c没有做相应的修改。
资源推荐
资源详情
资源评论
收起资源包目录
(ffmpeg tutorial)ffmpeg2.8 SDL2.0视频同步播放器 (340个子文件)
tutorial07.c 28KB
tutorial06.c 26KB
tutorial07 - 副本.c 26KB
tutorial07.c 26KB
tutorial06 - 副本.c 23KB
tutorial05.c 21KB
tutorial05 - 副本.c 21KB
audioPlay.c 20KB
tutorial04.c 19KB
tutorial04 - 副本.c 18KB
tutorial03副本.c 15KB
tutorial03.c 13KB
tutorial02.c 6KB
tutorial01.c 5KB
event_sdl2.cpp 3KB
avcodec-56.dll 20.27MB
avformat-56.dll 5.66MB
avfilter-5.dll 2.28MB
avdevice-56.dll 1.32MB
SDL2.dll 984KB
SDL2.dll 984KB
avutil-54.dll 471KB
swscale-3.dll 442KB
SDL.dll 300KB
SDL.dll 297KB
SDL.dll 297KB
SDL.dll 297KB
swresample-1.dll 274KB
postproc-53.dll 128KB
SDL_opengl.h 622KB
SDL_opengl.h 622KB
SDL_opengl.h 329KB
avcodec.h 178KB
SDL_opengles2.h 129KB
SDL_opengles2.h 129KB
avformat.h 102KB
avfilter.h 56KB
SDL_haptic.h 38KB
SDL_haptic.h 38KB
SDL_video.h 37KB
opt.h 37KB
pixfmt.h 33KB
SDL_video.h 33KB
SDL_video.h 33KB
SDL_render.h 32KB
SDL_render.h 32KB
SDL_events.h 26KB
SDL_events.h 26KB
frame.h 24KB
avio.h 22KB
SDL_audio.h 20KB
SDL_audio.h 20KB
SDL_hints.h 19KB
SDL_hints.h 19KB
swresample.h 19KB
SDL_surface.h 18KB
SDL_surface.h 18KB
intreadwrite.h 18KB
avdevice.h 18KB
SDL_stdinc.h 16KB
SDL_pixels.h 15KB
SDL_pixels.h 15KB
SDL_scancode.h 15KB
SDL_scancode.h 15KB
pixdesc.h 15KB
SDL_keycode.h 14KB
SDL_keycode.h 14KB
mem.h 14KB
common.h 14KB
old_pix_fmts.h 14KB
SDL_stdinc.h 14KB
SDL_stdinc.h 14KB
avstring.h 13KB
SDL_test_fuzzer.h 13KB
SDL_test_fuzzer.h 13KB
SDL_events.h 13KB
swscale.h 12KB
SDL_audio.h 11KB
SDL_assert.h 10KB
SDL_assert.h 10KB
log.h 10KB
old_codec_ids.h 10KB
SDL_gamecontroller.h 10KB
SDL_gamecontroller.h 10KB
samplefmt.h 10KB
SDL_thread.h 10KB
SDL_thread.h 10KB
buffer.h 10KB
channel_layout.h 9KB
SDL_atomic.h 9KB
SDL_atomic.h 9KB
avutil.h 8KB
imgutils.h 8KB
SDL_joystick.h 8KB
SDL_joystick.h 8KB
vdpau.h 8KB
dict.h 8KB
bprint.h 8KB
parseutils.h 7KB
buffersink.h 7KB
共 340 条
- 1
- 2
- 3
- 4
资源评论
- xx2211xx2017-08-22Severity Code Description Project File Line Suppression State Error C1083 无法打开包括文件:“inttypes.h”: No such file or directory tutorial04 c:\users\administrator\desktop\p\ffmpegtutorial\include\libavutil\common.h 34 这个错误怎么处理呢?ustb_atrx2018-01-02好久好久么有弄视频了,都忘的差不多了。看这个像是少 C++11 新类型int8_t 等类型的头文件
- maya8maya852015-11-08资源不错,对我的项目有一定的参考价值。ustb_atrx2016-01-04http://download.csdn.net/detail/ustb_atrx/9373517 有一份录像加录音的代码,因为代码有两处需要修改,没人评论,不能修改也不能评论, 所以在此说明一下,但愿下载资源的人能看到。第一处:CCameraDevice::Start(BOOL bCaptureMike)的函数中需要加一句m_bCaptureMike = bCaptureMike; 代码 。另外一处是:AudioUtil.cpp中dup_wchar_to_utf8(wchar_t *w)中的函数中WideCharToMultiByte的第一个参数都需要改成CP_UTF8 就可以得出录像加录音的视频文件了。
ustb_atrx
- 粉丝: 17
- 资源: 65
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
- 装修通用报价参考,基础施工项目+水电工程项目+瓦木项目,超级详细
- 三菱PLC例程源码Medocsequencegenerator
- 三菱PLC例程源码M1320磨头进出FX1s控制步进电机,有注释
- STRASSEN矩阵乘法算法(改进分治法·C语言)
- 前端.xmind前端.xmind前端.xmind前端.xmind前端.xmind
- 三菱PLC例程源码LOW-E玻璃镀膜线程序(三菱QPLC的)一万步带注释
- 三菱PLC例程源码LCD设备蚀刻机程序
- 三菱PLC例程源码LCD设备蚀刻机
- 全面前端开发指南:从基础到深入
- pvk2pfx 32位 Pvk2Pfx (Pvk2Pfx.exe) 是一种命令行工具,可将 .spc、.cer 和 .pvk 文
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功