http://blog.csdn.net/yangping1220/article/details/11232419
1、main()开始:
分别注册编解码器,复用以及解复用器
- avcodec_register_all();
- avdevice_register_all();
- av_register_all();
接着就是一些分配内存空间的代码
代码 略
- parse_options(argc, argv, options, opt_input_file);
- flags = SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER;
- SDL_Init (flags) <span style="white-space:pre"> </span>
- SDL_EventState(SDL_ACTIVEEVENT, SDL_IGNORE);
- SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE);
- SDL_EventState(SDL_SYSWMEVENT, SDL_IGNORE);
- SDL_EventState(SDL_USEREVENT, SDL_IGNORE);
- av_init_packet(&flush_pkt);
这个是重点:
- cur_stream = stream_open(input_filename, file_iformat);
2、具体分析stream_open()函数:
首先初始化了显示视频要的互斥锁,条件变量
- is->pictq_mutex = SDL_CreateMutex();
- is->pictq_cond = SDL_CreateCond();
-
- is->subpq_mutex = SDL_CreateMutex();
- is->subpq_cond = SDL_CreateCond();
-
- schedule_refresh(is, 40);
- is->parse_tid = SDL_CreateThread(decode_thread, is);
stream_open()函数调用结束。
3、接着分析decode_thread线程:
开始会初始化VideoState的部分参数
- static int decode_thread(void *arg)
- {
- VideoState *is = arg;
- AVFormatContext *ic;
- int err, i, ret, video_index, audio_index, subtitle_index;
- AVPacket pkt1, *pkt = &pkt1;
- AVFormatParameters params, *ap = ¶ms;
-
- video_index = -1;
- audio_index = -1;
- subtitle_index = -1;
- is->video_stream = -1;
- is->audio_stream = -1;
- is->subtitle_stream = -1;
-
- global_video_state = is;
- url_set_interrupt_cb(decode_interrupt_cb);
-
- memset(ap, 0, sizeof(*ap));
-
- ap->width = frame_width;
- ap->height= frame_height;
- ap->time_base= (AVRational){1, 25};
- ap->pix_fmt = frame_pix_fmt;
-
- err = av_open_input_file(&ic, is->filename, is->iformat, 0, ap);
-
- if (err < 0) {
- print_error(is->filename, err);
- ret = -1;
- goto fail;
- }
- is->ic = ic;
-
- if(genpts)
- ic->flags |= AVFMT_FLAG_GENPTS;
-
- err = av_find_stream_info(ic);
-
- if (err < 0) {
- fprintf(stderr, "%s: could not find codec parameters\n", is->filename);
- ret = -1;
- goto fail;
- }
- if(ic->pb)
- ic->pb->eof_reached= 0;
-
-
- if (start_time != AV_NOPTS_VALUE) {
- int64_t timestamp;
-
- timestamp = start_time;
-
- if (ic->start_time != AV_NOPTS_VALUE)
- timestamp += ic->start_time;
- ret = av_seek_frame(ic, -1, timestamp, AVSEEK_FLAG_BACKWARD);
- if (ret < 0) {
- fprintf(stderr, "%s: could not seek to position %0.3f\n",
- is->filename, (double)timestamp / AV_TIME_BASE);
- }
- }
-
- for(i = 0; i < ic->nb_streams; i++) {
- AVCodecContext *enc = ic->streams[i]->codec;
- ic->streams[i]->discard = AVDISCARD_ALL;
- switch(enc->codec_type) {
- case CODEC_TYPE_AUDIO:
- if (wanted_audio_stream-- >= 0 && !audio_disable)
- audio_index = i;
- break;
- case CODEC_TYPE_VIDEO:
- if (wanted_video_stream-- >= 0 && !video_disable)
- video_index = i;
- break;
- case CODEC_TYPE_SUBTITLE:
- if (wanted_subtitle_stream-- >= 0 && !video_disable)
- subtitle_index = i;
- break;
- default:
- break;
- }
- }
- if (show_status) {
- dump_format(ic, 0, is->filename, 0);
- dump_stream_info(ic);
- }
-
-
- if (audio_index >= 0) {
- stream_component_open(is, audio_index);
- }
-
- if (video_index >= 0) {
- stream_component_open(is, video_index);
-
- } else {
- if (!display_disable)
- is->show_audio = 1;
- }
-
- if (subtitle_index >= 0) {
- stream_component_open(is, subtitle_index);
- }
-
- if (is->video_stream < 0 && is->audio_stream < 0) {
- fprintf(stderr, "%s: could not open codecs\n", is->filename);
- ret = -1;
- goto fail;
- }
-
- for(;;) {
- if (is->abort_request)
- break;
- if (is->paused != is->last_paused) {
- is->last_paused = is->paused;
- if (is->paused)
- av_read_pause(ic);
- else
- av_read_play(ic);
- }
- #if CONFIG_RTSP_DEMUXER
- if (is->paused && !strcmp(ic->iformat->name, "rtsp")) {
-
-
- SDL_Delay(10);
- continue;
- }
- #endif
- if (is->seek_req) {
- int stream_index= -1;
- int64_t seek_target= is->seek_pos;
-
- if (is-> video_stream >= 0) stream_index= is-> video_stream;
- else if(is-> audio_stream >= 0) stream_index= is-> audio_stream;
- else if(is->subtitle_stream >= 0) stream_index= is->subtitle_stream;
-
- if(stream_index>=0){
- seek_target= av_rescale_q(seek_target, AV_TIME_BASE_Q, ic->streams[stream_index]->time_base);
- }
-
- ret = av_seek_frame(is->ic, stream_index, seek_target, is->seek_flags);
- if (ret < 0) {
- fprintf(stderr, "%s: error while seeking\n", is->ic->filename);
- }else{
- if (is->audio_stream >= 0) {
- packet_queue_flush(&is->audioq);
- packet_queue_put(&is->audioq, &flush_pkt);
- }
- if (is->subtitle_stream >= 0) {
- packet_queue_flush(&is->subtitleq);
- packet_queue_put(&is->subtitleq, &flush_pkt);
- }
- if (is->video_stream >= 0) {
- packet_queue_flush(&is->videoq);
- packet_queue_put(&is->videoq, &flush_pkt);
- }
- }
- is->seek_req = 0;
- }
-
-
- if (is->audioq.size > MAX_AUDIOQ_SIZE ||
- is->videoq.size > MAX_VIDEOQ_SIZE ||
- is->subtitleq.size > MAX_SUBTITLEQ_SIZE) {
-
- SDL_Delay(10);
- continue;
- }
- if(url_feof(ic->pb)) {
- av_init_packet(pkt);
- pkt->data=NULL;
- pkt->size=0;
- pkt->stream_index= is->video_stream;
- packet_queue_put(&is->videoq, pkt);
- continue;
- }
- ret = av_read_frame(ic, pkt);
- if (ret < 0) {
- if (ret != AVERROR_EOF && url_ferror(ic->pb) == 0) {
- SDL_Delay(100);
- continue;
- } else
- break;
- }
- if (pkt->stream_index == is->audio_stream) {
- packet_queue_put(&is->audioq, pkt);
- } else if (pkt->stream_index == is->video_stream) {
- packet_queue_put(&is->videoq, pkt);
- } else if (pkt->stream_index == is->subtitle_stream) {
- packet_queue_put(&is->subtitleq, pkt);
- } else {
- av_free_packet(pkt);
- }
- }
-
- while (!is->abort_request) {
- SDL_Delay(100);
- }
-
- ret = 0;
- fail:
-
- global_video_state = NULL;
-
-
- if (is->audio_stream >= 0)
- stream_component_close(is, is->audio_stream);
- if (is->video_stream >= 0)
- stream_component_close(is, is->video_stream);
- if (is->subtitle_stream >= 0)
- stream_component_close(is, is->subtitle_stream);
- if (is->ic) {
- av_close_input_file(is->ic);
- is->ic = NULL;
- }
- url_set_interrupt_cb(NULL);
-
- if (ret != 0) {
- SDL_Event event;
-
- event.type = FF_QUIT_EVENT;
- event.user.data1 = is;
- SDL_PushEvent(&event);
- }
- return 0;
- }
4、下面再来分析视频解码线程(函数为 ffplay.c / stream_component_open())
下面是解码线程
- static int stream_component_open(VideoState *is, int stream_index)
- {
- AVFormatContext *ic = is->ic;
- AVCodecContext *enc;
- AVCodec *codec;
- <strong>SDL_AudioSpec wanted_spec, spec;</strong>
-
- if (stream_index < 0 || stream_index >= ic->nb_streams)
- return -1;
- enc = ic->streams[stream_index]->codec;
-
-
- if (enc->codec_type == CODEC_TYPE_AUDIO) {
- if (enc->channels > 0) {
- enc->request_channels = FFMIN(2, enc->channels);
- } else {
- enc->request_channels = 2;
- }
- }
-
- codec = avcodec_find_decoder(enc->codec_id);
- enc->debug_mv = debug_mv;
- enc->debug = debug;
- enc->workaround_bugs = workaround_bugs;
- enc->lowres = lowres;
- if(lowres) enc->flags |= CODEC_FLAG_EMU_EDGE;
- enc->idct_algo= idct;
- if(fast) enc->flags2 |= CODEC_FLAG2_FAST;
- enc->skip_frame= skip_frame;
- enc->skip_idct= skip_idct;
- enc->skip_loop_filter= skip_loop_filter;
- enc->error_recognition= error_recognition;
- enc->error_concealment= error_concealment;
-
- set_context_opts(enc, avctx_opts[enc->codec_type], 0);
-
- if (!codec ||
- avcodec_open(enc, codec) < 0)
- return -1;
-
-
- if (enc->codec_type == CODEC_TYPE_AUDIO) {
- wanted_spec.freq = enc->sample_rate;
- wanted_spec.format = AUDIO_S16SYS;
- wanted_spec.channels = enc->channels;
- wanted_spec.silence = 0;
- wanted_spec.samples = SDL_AUDIO_BUFFER_SIZE;
- wanted_spec.callback = <strong><span style="color:#ff0000;">sdl_audio_callback</span></strong>;
- wanted_spec.userdata = is;
- if (SDL_OpenAudio(&wanted_spec, &spec) < 0) {
- fprintf(stderr, "SDL_OpenAudio: %s\n", SDL_GetError());
- return -1;
- }
- is->audio_hw_buf_size = spec.size;
- is->audio_src_fmt= SAMPLE_FMT_S16;
- }
-
- if(thread_count>1)
- avcodec_thread_init(enc, thread_count);
- enc->thread_count= thread_count;
- ic->streams[stream_index]->discard = AVDISCARD_DEFAULT;
- switch(enc->codec_type) {
- case CODEC_TYPE_AUDIO:
- is->audio_stream = stream_index;
- is->audio_st = ic->streams[stream_index];
- is->audio_buf_size = 0;
- is->audio_buf_index = 0;
-
-
- is->audio_diff_avg_coef = exp(log(0.01) / AUDIO_DIFF_AVG_NB);
- is->audio_diff_avg_count = 0;
-
-
- is->audio_diff_threshold = 2.0 * SDL_AUDIO_BUFFER_SIZE / enc->sample_rate;
-
- memset(&is->audio_pkt, 0, sizeof(is->audio_pkt));
- packet_queue_init(&is->audioq);
- SDL_PauseAudio(0);
- break;
- case CODEC_TYPE_VIDEO:
- is->video_stream = stream_index;
- is->video_st = ic->streams[stream_index];
-
- is->frame_last_delay = 40e-3;
- is->frame_timer = (double)av_gettime() / 1000000.0;
- is->video_current_pts_time = av_gettime();
-
- packet_queue_init(&is->videoq);
- is->video_tid = SDL_CreateThread(video_thread, is);
- break;
- case CODEC_TYPE_SUBTITLE:
- is->subtitle_stream = stream_index;
- is->subtitle_st = ic->streams[stream_index];
- packet_queue_init(&is->subtitleq);
-
- is->subtitle_tid = SDL_CreateThread(subtitle_thread, is);
- break;
- default:
- break;
- }
- return 0;
- }
5、接着分析video_thread线程:
- static int video_thread(void *arg)
- {
- VideoState *is = arg;
- AVPacket pkt1, *pkt = &pkt1;
- int len1, got_picture;
- AVFrame *frame= avcodec_alloc_frame();
- double pts;
-
- for(;;) {
- while (is->paused && !is->videoq.abort_request) {
- SDL_Delay(10);
- }
- if (packet_queue_get(&is->videoq, pkt, 1) < 0)
- break;
-
- if(pkt->data == flush_pkt.data){
- avcodec_flush_buffers(is->video_st->codec);
- continue;
- }
-
-
-
- is->video_st->codec->reordered_opaque= pkt->pts;
- len1 = avcodec_decode_video(is->video_st->codec,
- frame, &got_picture,
- pkt->data, pkt->size);
-
- if( (decoder_reorder_pts || pkt->dts == AV_NOPTS_VALUE)
- && frame->reordered_opaque != AV_NOPTS_VALUE)
- pts= frame->reordered_opaque;
- else if(pkt->dts != AV_NOPTS_VALUE)
- pts= pkt->dts;
- else
- pts= 0;
- pts *= av_q2d(is->video_st->time_base);
-
-
-
- if (got_picture) {
- if (output_picture2(is, frame, pts) < 0)
- goto the_end;
- }
- av_free_packet(pkt);
- if (step)
- if (cur_stream)
- stream_pause(cur_stream);
- }
- the_end:
- av_free(frame);
- return 0;
- }
6、最后分析一下main中的event_loop()
-
- static void event_loop(void)
- {
- SDL_Event event;
- double incr, pos, frac;
-
- for(;;) {
- SDL_WaitEvent(&event);
- switch(event.type) {
- case SDL_KEYDOWN:
- switch(event.key.keysym.sym) {
- case SDLK_ESCAPE:
- case SDLK_q:
- do_exit();
- break;
- case SDLK_f:
- toggle_full_screen();
- break;
- case SDLK_p:
- case SDLK_SPACE:
- toggle_pause();
- break;
- case SDLK_s:
- step_to_next_frame();
- break;
- case SDLK_a:
- if (cur_stream)
- stream_cycle_channel(cur_stream, CODEC_TYPE_AUDIO);
- break;
- case SDLK_v:
- if (cur_stream)
- stream_cycle_channel(cur_stream, CODEC_TYPE_VIDEO);
- break;
- case SDLK_t:
- if (cur_stream)
- stream_cycle_channel(cur_stream, CODEC_TYPE_SUBTITLE);
- break;
- case SDLK_w:
- toggle_audio_display();
- break;
- case SDLK_LEFT:
- incr = -10.0;
- goto do_seek;
- case SDLK_RIGHT:
- incr = 10.0;
- goto do_seek;
- case SDLK_UP:
- incr = 60.0;
- goto do_seek;
- case SDLK_DOWN:
- incr = -60.0;
- do_seek:
- if (cur_stream) {
- if (seek_by_bytes) {
- pos = url_ftell(cur_stream->ic->pb);
- if (cur_stream->ic->bit_rate)
- incr *= cur_stream->ic->bit_rate / 60.0;
- else
- incr *= 180000.0;
- pos += incr;
- stream_seek(cur_stream, pos, incr);
- } else {
- pos = get_master_clock(cur_stream);
- pos += incr;
- stream_seek(cur_stream, (int64_t)(pos * AV_TIME_BASE), incr);
- }
- }
- break;
- default:
- break;
- }
- break;
- case SDL_MOUSEBUTTONDOWN:
- if (cur_stream) {
- int ns, hh, mm, ss;
- int tns, thh, tmm, tss;
- tns = cur_stream->ic->duration/1000000LL;
- thh = tns/3600;
- tmm = (tns%3600)/60;
- tss = (tns%60);
- frac = (double)event.button.x/(double)cur_stream->width;
- ns = frac*tns;
- hh = ns/3600;
- mm = (ns%3600)/60;
- ss = (ns%60);
- fprintf(stderr, "Seek to %2.0f%% (%2d:%02d:%02d) of total duration (%2d:%02d:%02d) \n", frac*100,
- hh, mm, ss, thh, tmm, tss);
- stream_seek(cur_stream, (int64_t)(cur_stream->ic->start_time+frac*cur_stream->ic->duration), 0);
- }
- break;
- case SDL_VIDEORESIZE:
- if (cur_stream) {
- screen = SDL_SetVideoMode(event.resize.w, event.resize.h, 0,
- SDL_HWSURFACE|SDL_RESIZABLE|SDL_ASYNCBLIT|SDL_HWACCEL);
- screen_width = cur_stream->width = event.resize.w;
- screen_height= cur_stream->height= event.resize.h;
- }
- break;
- case SDL_QUIT:
- case FF_QUIT_EVENT:
- do_exit();
- break;
- case FF_ALLOC_EVENT:
- video_open(event.user.data1);
- alloc_picture(event.user.data1);
- break;
- case FF_REFRESH_EVENT:
- video_refresh_timer(event.user.data1);
- break;
- default:
- break;
- }
- }