📄 ffplay.c.svn-base
字号:
if (SDL_OpenAudio(&wanted_spec, &spec) < 0) { fprintf(stderr, "SDL_OpenAudio: %s\n", SDL_GetError()); return -1; } is->audio_hw_buf_size = spec.size; } if(thread_count>1) avcodec_thread_init(enc, thread_count); enc->thread_count= thread_count; 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; /* init averaging filter */ is->audio_diff_avg_coef = exp(log(0.01) / AUDIO_DIFF_AVG_NB); is->audio_diff_avg_count = 0; /* since we do not have a precise anough audio fifo fullness, we correct audio sync only if larger than this threshold */ 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); enc-> get_buffer= my_get_buffer; enc->release_buffer= my_release_buffer; 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;}static void stream_component_close(VideoState *is, int stream_index){ AVFormatContext *ic = is->ic; AVCodecContext *enc; if (stream_index < 0 || stream_index >= ic->nb_streams) return; enc = ic->streams[stream_index]->codec; switch(enc->codec_type) { case CODEC_TYPE_AUDIO: packet_queue_abort(&is->audioq); SDL_CloseAudio(); packet_queue_end(&is->audioq); break; case CODEC_TYPE_VIDEO: packet_queue_abort(&is->videoq); /* note: we also signal this mutex to make sure we deblock the video thread in all cases */ SDL_LockMutex(is->pictq_mutex); SDL_CondSignal(is->pictq_cond); SDL_UnlockMutex(is->pictq_mutex); SDL_WaitThread(is->video_tid, NULL); packet_queue_end(&is->videoq); break; case CODEC_TYPE_SUBTITLE: packet_queue_abort(&is->subtitleq); /* note: we also signal this mutex to make sure we deblock the video thread in all cases */ SDL_LockMutex(is->subpq_mutex); is->subtitle_stream_changed = 1; SDL_CondSignal(is->subpq_cond); SDL_UnlockMutex(is->subpq_mutex); SDL_WaitThread(is->subtitle_tid, NULL); packet_queue_end(&is->subtitleq); break; default: break; } avcodec_close(enc); switch(enc->codec_type) { case CODEC_TYPE_AUDIO: is->audio_st = NULL; is->audio_stream = -1; break; case CODEC_TYPE_VIDEO: is->video_st = NULL; is->video_stream = -1; break; case CODEC_TYPE_SUBTITLE: is->subtitle_st = NULL; is->subtitle_stream = -1; break; default: break; }}static void dump_stream_info(const AVFormatContext *s){ if (s->track != 0) fprintf(stderr, "Track: %d\n", s->track); if (s->title[0] != '\0') fprintf(stderr, "Title: %s\n", s->title); if (s->author[0] != '\0') fprintf(stderr, "Author: %s\n", s->author); if (s->copyright[0] != '\0') fprintf(stderr, "Copyright: %s\n", s->copyright); if (s->comment[0] != '\0') fprintf(stderr, "Comment: %s\n", s->comment); if (s->album[0] != '\0') fprintf(stderr, "Album: %s\n", s->album); if (s->year != 0) fprintf(stderr, "Year: %d\n", s->year); if (s->genre[0] != '\0') fprintf(stderr, "Genre: %s\n", s->genre);}/* since we have only one decoding thread, we can use a global variable instead of a thread local variable */static VideoState *global_video_state;static int decode_interrupt_cb(void){ return (global_video_state && global_video_state->abort_request);}/* this thread gets the stream from the disk or the network */static int decode_thread(void *arg){ VideoState *is = arg; AVFormatContext *ic; int err, i, ret, video_index, audio_index; AVPacket pkt1, *pkt = &pkt1; AVFormatParameters params, *ap = ¶ms; video_index = -1; audio_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; //FIXME hack, ffplay maybe should not use url_feof() to test for the end /* if seeking requested, we execute it */ if (start_time != AV_NOPTS_VALUE) { int64_t timestamp; timestamp = start_time; /* add the stream 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; switch(enc->codec_type) { case CODEC_TYPE_AUDIO: if ((audio_index < 0 || wanted_audio_stream-- > 0) && !audio_disable) audio_index = i; break; case CODEC_TYPE_VIDEO: if ((video_index < 0 || wanted_video_stream-- > 0) && !video_disable) video_index = i; break; default: break; } } if (show_status) { dump_format(ic, 0, is->filename, 0); dump_stream_info(ic); } /* open the streams */ 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 (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 defined(CONFIG_RTSP_DEMUXER) || defined(CONFIG_MMSH_PROTOCOL) if (is->paused && (!strcmp(ic->iformat->name, "rtsp") || (ic->pb && !strcmp(url_fileno(ic->pb)->prot->name, "mmsh")))) { /* wait 10 ms to avoid trying to get another packet */ /* XXX: horrible */ 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 the queue are full, no need to read more */ if (is->audioq.size > MAX_AUDIOQ_SIZE || is->videoq.size > MAX_VIDEOQ_SIZE || is->subtitleq.size > MAX_SUBTITLEQ_SIZE || url_feof(ic->pb)) { /* wait 10 ms */ SDL_Delay(10); continue; } ret = av_read_frame(ic, pkt); if (ret < 0) { if (url_ferror(ic->pb) == 0) { SDL_Delay(100); /* wait for user event */ 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); } } /* wait until the end */ while (!is->abort_request) { SDL_Delay(100); } ret = 0; fail: /* disable interrupting */ global_video_state = NULL; /* close each stream */ 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; /* safety */ } 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;}static VideoState *stream_open(const char *filename, AVInputFormat *iformat){ VideoState *is; is = av_mallocz(sizeof(VideoState)); if (!is) return NULL; av_strlcpy(is->filename, filename, sizeof(is->filename)); is->iformat = iformat; is->ytop = 0; is->xleft = 0; /* start video display */ is->pictq_mutex = SDL_CreateMutex(); is->pictq_cond = SDL_CreateCond(); is->subpq_mutex = SDL_CreateMutex(); is->subpq_cond = SDL_CreateCond(); /* add the refresh timer to draw the picture */ schedule_refresh(is, 40); is->av_sync_type = av_sync_type; is->parse_tid = SDL_CreateThread(decode_thread, is); if (!is->parse_tid) { av_free(is); return NULL; } return is;}static void stream_close(VideoState *is){ VideoPicture *vp; int i; /* XXX: use a special url_shutdown call to abort parse cleanly */ is->abort_request = 1; SDL_WaitThread(is->parse_tid, NULL); /* free all pictures */ for(i=0;i<VIDEO_PICTURE_QUEUE_SIZE; i++) { vp = &is->pictq[i]; if (vp->bmp) { SDL_FreeYUVOverlay(vp->bmp); vp->bmp = NULL; } } SDL_DestroyMutex(is->pictq_mutex); SDL_DestroyCond(is->pictq_cond); SDL_DestroyMutex(is->subpq_mutex); SDL_DestroyCond(is->subpq_cond);}static void stream_cycle_channel(VideoState *is, int codec_type){ AVFormatContext *ic = is->ic; int start_index, stream_index; AVStream *st; if (codec_type == CODEC_TYPE_VIDEO) start_index = is->video_stream; else if (codec_type == CODEC_TYPE_AUDIO) start_index = is->audio_stream; else start_index = is->subtitle_stream; if (st
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -