X-Git-Url: https://git.piment-noir.org/?p=deb_ffmpeg.git;a=blobdiff_plain;f=ffmpeg%2Fffplay.c;h=1914a6692f2184d71f08478f74aa668f34028627;hp=833b5b12cf43a5451838ffdb59444b76f4b22db9;hb=f6fa7814ccfe3e76514b36cf04f5cd3cb657c8cf;hpb=2ba45a602cbfa7b771effba9b11bb4245c21bc00 diff --git a/ffmpeg/ffplay.c b/ffmpeg/ffplay.c index 833b5b1..1914a66 100644 --- a/ffmpeg/ffplay.c +++ b/ffmpeg/ffplay.c @@ -121,25 +121,8 @@ typedef struct PacketQueue { #define VIDEO_PICTURE_QUEUE_SIZE 3 #define SUBPICTURE_QUEUE_SIZE 16 - -typedef struct VideoPicture { - double pts; // presentation timestamp for this picture - double duration; // estimated duration based on frame rate - int64_t pos; // byte position in file - SDL_Overlay *bmp; - int width, height; /* source height & width */ - int allocated; - int reallocate; - int serial; - - AVRational sar; -} VideoPicture; - -typedef struct SubPicture { - double pts; /* presentation time stamp for this picture */ - AVSubtitle sub; - int serial; -} SubPicture; +#define SAMPLE_QUEUE_SIZE 9 +#define FRAME_QUEUE_SIZE FFMAX(SAMPLE_QUEUE_SIZE, FFMAX(VIDEO_PICTURE_QUEUE_SIZE, SUBPICTURE_QUEUE_SIZE)) typedef struct AudioParams { int freq; @@ -160,15 +143,61 @@ typedef struct Clock { int *queue_serial; /* pointer to the current packet queue serial, used for obsolete clock detection */ } Clock; +/* Common struct for handling all types of decoded data and allocated render buffers. */ +typedef struct Frame { + AVFrame *frame; + AVSubtitle sub; + int serial; + double pts; /* presentation timestamp for the frame */ + double duration; /* estimated duration of the frame */ + int64_t pos; /* byte position of the frame in the input file */ + SDL_Overlay *bmp; + int allocated; + int reallocate; + int width; + int height; + AVRational sar; +} Frame; + +typedef struct FrameQueue { + Frame queue[FRAME_QUEUE_SIZE]; + int rindex; + int windex; + int size; + int max_size; + int keep_last; + int rindex_shown; + SDL_mutex *mutex; + SDL_cond *cond; + PacketQueue *pktq; +} FrameQueue; + enum { AV_SYNC_AUDIO_MASTER, /* default choice */ AV_SYNC_VIDEO_MASTER, AV_SYNC_EXTERNAL_CLOCK, /* synchronize to an external clock */ }; +typedef struct Decoder { + AVPacket pkt; + AVPacket pkt_temp; + PacketQueue *queue; + AVCodecContext *avctx; + int pkt_serial; + int finished; + int flushed; + int packet_pending; + SDL_cond *empty_queue_cond; + int64_t start_pts; + AVRational start_pts_tb; + int64_t next_pts; + AVRational next_pts_tb; +} Decoder; + typedef struct VideoState { SDL_Thread *read_tid; SDL_Thread *video_tid; + SDL_Thread *audio_tid; AVInputFormat *iformat; int no_background; int abort_request; @@ -183,13 +212,19 @@ typedef struct VideoState { int read_pause_return; AVFormatContext *ic; int realtime; - int audio_finished; - int video_finished; Clock audclk; Clock vidclk; Clock extclk; + FrameQueue pictq; + FrameQueue subpq; + FrameQueue sampq; + + Decoder auddec; + Decoder viddec; + Decoder subdec; + int audio_stream; int av_sync_type; @@ -210,11 +245,6 @@ typedef struct VideoState { unsigned int audio_buf1_size; int audio_buf_index; /* in bytes */ int audio_write_buf_size; - int audio_buf_frames_pending; - AVPacket audio_pkt_temp; - AVPacket audio_pkt; - int audio_pkt_temp_serial; - int audio_last_serial; struct AudioParams audio_src; #if CONFIG_AVFILTER struct AudioParams audio_filter_src; @@ -223,8 +253,6 @@ typedef struct VideoState { struct SwrContext *swr_ctx; int frame_drops_early; int frame_drops_late; - AVFrame *frame; - int64_t audio_frame_next_pts; enum ShowMode { SHOW_MODE_NONE = -1, SHOW_MODE_VIDEO = 0, SHOW_MODE_WAVES, SHOW_MODE_RDFT, SHOW_MODE_NB @@ -242,10 +270,6 @@ typedef struct VideoState { int subtitle_stream; AVStream *subtitle_st; PacketQueue subtitleq; - SubPicture subpq[SUBPICTURE_QUEUE_SIZE]; - int subpq_size, subpq_rindex, subpq_windex; - SDL_mutex *subpq_mutex; - SDL_cond *subpq_cond; double frame_timer; double frame_last_returned_time; @@ -253,12 +277,7 @@ typedef struct VideoState { int video_stream; AVStream *video_st; PacketQueue videoq; - int64_t video_current_pos; // current displayed file pos double max_frame_duration; // maximum duration of a frame - above this, we consider the jump a timestamp discontinuity - VideoPicture pictq[VIDEO_PICTURE_QUEUE_SIZE]; - int pictq_size, pictq_rindex, pictq_windex, pictq_rindex_shown; - SDL_mutex *pictq_mutex; - SDL_cond *pictq_cond; #if !CONFIG_AVFILTER struct SwsContext *img_convert_ctx; #endif @@ -306,7 +325,6 @@ static int show_status = 1; static int av_sync_type = AV_SYNC_AUDIO_MASTER; static int64_t start_time = AV_NOPTS_VALUE; static int64_t duration = AV_NOPTS_VALUE; -static int workaround_bugs = 1; static int fast = 0; static int genpts = 0; static int lowres = 0; @@ -371,6 +389,8 @@ int64_t get_valid_channel_layout(int64_t channel_layout, int channels) return 0; } +static void free_picture(Frame *vp); + static int packet_queue_put_private(PacketQueue *q, AVPacket *pkt) { MyAVPacketList *pkt1; @@ -517,6 +537,246 @@ static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block, int *seria return ret; } +static void decoder_init(Decoder *d, AVCodecContext *avctx, PacketQueue *queue, SDL_cond *empty_queue_cond) { + memset(d, 0, sizeof(Decoder)); + d->avctx = avctx; + d->queue = queue; + d->empty_queue_cond = empty_queue_cond; + d->start_pts = AV_NOPTS_VALUE; +} + +static int decoder_decode_frame(Decoder *d, AVFrame *frame, AVSubtitle *sub) { + int got_frame = 0; + + d->flushed = 0; + + do { + int ret = -1; + + if (d->queue->abort_request) + return -1; + + if (!d->packet_pending || d->queue->serial != d->pkt_serial) { + AVPacket pkt; + do { + if (d->queue->nb_packets == 0) + SDL_CondSignal(d->empty_queue_cond); + if (packet_queue_get(d->queue, &pkt, 1, &d->pkt_serial) < 0) + return -1; + if (pkt.data == flush_pkt.data) { + avcodec_flush_buffers(d->avctx); + d->finished = 0; + d->flushed = 1; + d->next_pts = d->start_pts; + d->next_pts_tb = d->start_pts_tb; + } + } while (pkt.data == flush_pkt.data || d->queue->serial != d->pkt_serial); + av_free_packet(&d->pkt); + d->pkt_temp = d->pkt = pkt; + d->packet_pending = 1; + } + + switch (d->avctx->codec_type) { + case AVMEDIA_TYPE_VIDEO: + ret = avcodec_decode_video2(d->avctx, frame, &got_frame, &d->pkt_temp); + if (got_frame) { + if (decoder_reorder_pts == -1) { + frame->pts = av_frame_get_best_effort_timestamp(frame); + } else if (decoder_reorder_pts) { + frame->pts = frame->pkt_pts; + } else { + frame->pts = frame->pkt_dts; + } + } + break; + case AVMEDIA_TYPE_AUDIO: + ret = avcodec_decode_audio4(d->avctx, frame, &got_frame, &d->pkt_temp); + if (got_frame) { + AVRational tb = (AVRational){1, frame->sample_rate}; + if (frame->pts != AV_NOPTS_VALUE) + frame->pts = av_rescale_q(frame->pts, d->avctx->time_base, tb); + else if (frame->pkt_pts != AV_NOPTS_VALUE) + frame->pts = av_rescale_q(frame->pkt_pts, av_codec_get_pkt_timebase(d->avctx), tb); + else if (d->next_pts != AV_NOPTS_VALUE) + frame->pts = av_rescale_q(d->next_pts, d->next_pts_tb, tb); + if (frame->pts != AV_NOPTS_VALUE) { + d->next_pts = frame->pts + frame->nb_samples; + d->next_pts_tb = tb; + } + } + break; + case AVMEDIA_TYPE_SUBTITLE: + ret = avcodec_decode_subtitle2(d->avctx, sub, &got_frame, &d->pkt_temp); + break; + } + + if (ret < 0) { + d->packet_pending = 0; + } else { + d->pkt_temp.dts = + d->pkt_temp.pts = AV_NOPTS_VALUE; + if (d->pkt_temp.data) { + if (d->avctx->codec_type != AVMEDIA_TYPE_AUDIO) + ret = d->pkt_temp.size; + d->pkt_temp.data += ret; + d->pkt_temp.size -= ret; + if (d->pkt_temp.size <= 0) + d->packet_pending = 0; + } else { + if (!got_frame) { + d->packet_pending = 0; + d->finished = d->pkt_serial; + } + } + } + } while (!got_frame && !d->finished); + + return got_frame; +} + +static void decoder_destroy(Decoder *d) { + av_free_packet(&d->pkt); +} + +static void frame_queue_unref_item(Frame *vp) +{ + av_frame_unref(vp->frame); + avsubtitle_free(&vp->sub); +} + +static int frame_queue_init(FrameQueue *f, PacketQueue *pktq, int max_size, int keep_last) +{ + int i; + memset(f, 0, sizeof(FrameQueue)); + if (!(f->mutex = SDL_CreateMutex())) + return AVERROR(ENOMEM); + if (!(f->cond = SDL_CreateCond())) + return AVERROR(ENOMEM); + f->pktq = pktq; + f->max_size = FFMIN(max_size, FRAME_QUEUE_SIZE); + f->keep_last = !!keep_last; + for (i = 0; i < f->max_size; i++) + if (!(f->queue[i].frame = av_frame_alloc())) + return AVERROR(ENOMEM); + return 0; +} + +static void frame_queue_destory(FrameQueue *f) +{ + int i; + for (i = 0; i < f->max_size; i++) { + Frame *vp = &f->queue[i]; + frame_queue_unref_item(vp); + av_frame_free(&vp->frame); + free_picture(vp); + } + SDL_DestroyMutex(f->mutex); + SDL_DestroyCond(f->cond); +} + +static void frame_queue_signal(FrameQueue *f) +{ + SDL_LockMutex(f->mutex); + SDL_CondSignal(f->cond); + SDL_UnlockMutex(f->mutex); +} + +static Frame *frame_queue_peek(FrameQueue *f) +{ + return &f->queue[(f->rindex + f->rindex_shown) % f->max_size]; +} + +static Frame *frame_queue_peek_next(FrameQueue *f) +{ + return &f->queue[(f->rindex + f->rindex_shown + 1) % f->max_size]; +} + +static Frame *frame_queue_peek_last(FrameQueue *f) +{ + return &f->queue[f->rindex]; +} + +static Frame *frame_queue_peek_writable(FrameQueue *f) +{ + /* wait until we have space to put a new frame */ + SDL_LockMutex(f->mutex); + while (f->size >= f->max_size && + !f->pktq->abort_request) { + SDL_CondWait(f->cond, f->mutex); + } + SDL_UnlockMutex(f->mutex); + + if (f->pktq->abort_request) + return NULL; + + return &f->queue[f->windex]; +} + +static Frame *frame_queue_peek_readable(FrameQueue *f) +{ + /* wait until we have a readable a new frame */ + SDL_LockMutex(f->mutex); + while (f->size - f->rindex_shown <= 0 && + !f->pktq->abort_request) { + SDL_CondWait(f->cond, f->mutex); + } + SDL_UnlockMutex(f->mutex); + + if (f->pktq->abort_request) + return NULL; + + return &f->queue[(f->rindex + f->rindex_shown) % f->max_size]; +} + +static void frame_queue_push(FrameQueue *f) +{ + if (++f->windex == f->max_size) + f->windex = 0; + SDL_LockMutex(f->mutex); + f->size++; + SDL_CondSignal(f->cond); + SDL_UnlockMutex(f->mutex); +} + +static void frame_queue_next(FrameQueue *f) +{ + if (f->keep_last && !f->rindex_shown) { + f->rindex_shown = 1; + return; + } + frame_queue_unref_item(&f->queue[f->rindex]); + if (++f->rindex == f->max_size) + f->rindex = 0; + SDL_LockMutex(f->mutex); + f->size--; + SDL_CondSignal(f->cond); + SDL_UnlockMutex(f->mutex); +} + +/* jump back to the previous frame if available by resetting rindex_shown */ +static int frame_queue_prev(FrameQueue *f) +{ + int ret = f->rindex_shown; + f->rindex_shown = 0; + return ret; +} + +/* return the number of undisplayed frames in the queue */ +static int frame_queue_nb_remaining(FrameQueue *f) +{ + return f->size - f->rindex_shown; +} + +/* return last shown position */ +static int64_t frame_queue_last_pos(FrameQueue *f) +{ + Frame *fp = &f->queue[f->rindex]; + if (f->rindex_shown && fp->serial == f->pktq->serial) + return fp->pos; + else + return -1; +} + static inline void fill_rectangle(SDL_Surface *screen, int x, int y, int w, int h, int color, int update) { @@ -795,7 +1055,7 @@ static void blend_subrect(AVPicture *dst, const AVSubtitleRect *rect, int imgw, } } -static void free_picture(VideoPicture *vp) +static void free_picture(Frame *vp) { if (vp->bmp) { SDL_FreeYUVOverlay(vp->bmp); @@ -803,11 +1063,6 @@ static void free_picture(VideoPicture *vp) } } -static void free_subpicture(SubPicture *sp) -{ - avsubtitle_free(&sp->sub); -} - static void calculate_display_rect(SDL_Rect *rect, int scr_xleft, int scr_ytop, int scr_width, int scr_height, int pic_width, int pic_height, AVRational pic_sar) @@ -841,17 +1096,17 @@ static void calculate_display_rect(SDL_Rect *rect, static void video_image_display(VideoState *is) { - VideoPicture *vp; - SubPicture *sp; + Frame *vp; + Frame *sp; AVPicture pict; SDL_Rect rect; int i; - vp = &is->pictq[(is->pictq_rindex + is->pictq_rindex_shown) % VIDEO_PICTURE_QUEUE_SIZE]; + vp = frame_queue_peek(&is->pictq); if (vp->bmp) { if (is->subtitle_st) { - if (is->subpq_size > 0) { - sp = &is->subpq[is->subpq_rindex]; + if (frame_queue_nb_remaining(&is->subpq) > 0) { + sp = frame_queue_peek(&is->subpq); if (vp->pts >= sp->pts + ((float) sp->sub.start_display_time / 1000)) { SDL_LockYUVOverlay (vp->bmp); @@ -1033,7 +1288,6 @@ static void video_audio_display(VideoState *s) static void stream_close(VideoState *is) { - int i; /* XXX: use a special url_shutdown call to abort parse cleanly */ is->abort_request = 1; SDL_WaitThread(is->read_tid, NULL); @@ -1042,14 +1296,9 @@ static void stream_close(VideoState *is) packet_queue_destroy(&is->subtitleq); /* free all pictures */ - for (i = 0; i < VIDEO_PICTURE_QUEUE_SIZE; i++) - free_picture(&is->pictq[i]); - for (i = 0; i < SUBPICTURE_QUEUE_SIZE; i++) - free_subpicture(&is->subpq[i]); - SDL_DestroyMutex(is->pictq_mutex); - SDL_DestroyCond(is->pictq_cond); - SDL_DestroyMutex(is->subpq_mutex); - SDL_DestroyCond(is->subpq_cond); + frame_queue_destory(&is->pictq); + frame_queue_destory(&is->sampq); + frame_queue_destory(&is->subpq); SDL_DestroyCond(is->continue_read_thread); #if !CONFIG_AVFILTER sws_freeContext(is->img_convert_ctx); @@ -1088,7 +1337,7 @@ static void set_default_window_size(int width, int height, AVRational sar) default_height = rect.h; } -static int video_open(VideoState *is, int force_set_video_mode, VideoPicture *vp) +static int video_open(VideoState *is, int force_set_video_mode, Frame *vp) { int flags = SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL; int w,h; @@ -1308,7 +1557,7 @@ static double compute_target_delay(double delay, VideoState *is) return delay; } -static double vp_duration(VideoState *is, VideoPicture *vp, VideoPicture *nextvp) { +static double vp_duration(VideoState *is, Frame *vp, Frame *nextvp) { if (vp->serial == nextvp->serial) { double duration = nextvp->pts - vp->pts; if (isnan(duration) || duration <= 0 || duration > is->max_frame_duration) @@ -1320,38 +1569,10 @@ static double vp_duration(VideoState *is, VideoPicture *vp, VideoPicture *nextvp } } -/* return the number of undisplayed pictures in the queue */ -static int pictq_nb_remaining(VideoState *is) { - return is->pictq_size - is->pictq_rindex_shown; -} - -/* jump back to the previous picture if available by resetting rindex_shown */ -static int pictq_prev_picture(VideoState *is) { - int ret = is->pictq_rindex_shown; - is->pictq_rindex_shown = 0; - return ret; -} - -static void pictq_next_picture(VideoState *is) { - if (!is->pictq_rindex_shown) { - is->pictq_rindex_shown = 1; - return; - } - /* update queue size and signal for next picture */ - if (++is->pictq_rindex == VIDEO_PICTURE_QUEUE_SIZE) - is->pictq_rindex = 0; - - SDL_LockMutex(is->pictq_mutex); - is->pictq_size--; - SDL_CondSignal(is->pictq_cond); - SDL_UnlockMutex(is->pictq_mutex); -} - static void update_video_pts(VideoState *is, double pts, int64_t pos, int serial) { /* update current video pts */ set_clock(&is->vidclk, pts, serial); sync_clock_to_slave(&is->extclk, &is->vidclk); - is->video_current_pos = pos; } /* called to display each frame */ @@ -1360,7 +1581,7 @@ static void video_refresh(void *opaque, double *remaining_time) VideoState *is = opaque; double time; - SubPicture *sp, *sp2; + Frame *sp, *sp2; if (!is->paused && get_master_sync_type(is) == AV_SYNC_EXTERNAL_CLOCK && is->realtime) check_external_clock_speed(is); @@ -1377,21 +1598,20 @@ static void video_refresh(void *opaque, double *remaining_time) if (is->video_st) { int redisplay = 0; if (is->force_refresh) - redisplay = pictq_prev_picture(is); + redisplay = frame_queue_prev(&is->pictq); retry: - if (pictq_nb_remaining(is) == 0) { + if (frame_queue_nb_remaining(&is->pictq) == 0) { // nothing to do, no picture to display in the queue } else { double last_duration, duration, delay; - VideoPicture *vp, *lastvp; + Frame *vp, *lastvp; /* dequeue the picture */ - lastvp = &is->pictq[is->pictq_rindex]; - vp = &is->pictq[(is->pictq_rindex + is->pictq_rindex_shown) % VIDEO_PICTURE_QUEUE_SIZE]; + lastvp = frame_queue_peek_last(&is->pictq); + vp = frame_queue_peek(&is->pictq); if (vp->serial != is->videoq.serial) { - pictq_next_picture(is); - is->video_current_pos = -1; + frame_queue_next(&is->pictq); redisplay = 0; goto retry; } @@ -1419,29 +1639,29 @@ retry: if (delay > 0 && time - is->frame_timer > AV_SYNC_THRESHOLD_MAX) is->frame_timer = time; - SDL_LockMutex(is->pictq_mutex); + SDL_LockMutex(is->pictq.mutex); if (!redisplay && !isnan(vp->pts)) update_video_pts(is, vp->pts, vp->pos, vp->serial); - SDL_UnlockMutex(is->pictq_mutex); + SDL_UnlockMutex(is->pictq.mutex); - if (pictq_nb_remaining(is) > 1) { - VideoPicture *nextvp = &is->pictq[(is->pictq_rindex + is->pictq_rindex_shown + 1) % VIDEO_PICTURE_QUEUE_SIZE]; + if (frame_queue_nb_remaining(&is->pictq) > 1) { + Frame *nextvp = frame_queue_peek_next(&is->pictq); duration = vp_duration(is, vp, nextvp); if(!is->step && (redisplay || framedrop>0 || (framedrop && get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER)) && time > is->frame_timer + duration){ if (!redisplay) is->frame_drops_late++; - pictq_next_picture(is); + frame_queue_next(&is->pictq); redisplay = 0; goto retry; } } if (is->subtitle_st) { - while (is->subpq_size > 0) { - sp = &is->subpq[is->subpq_rindex]; + while (frame_queue_nb_remaining(&is->subpq) > 0) { + sp = frame_queue_peek(&is->subpq); - if (is->subpq_size > 1) - sp2 = &is->subpq[(is->subpq_rindex + 1) % SUBPICTURE_QUEUE_SIZE]; + if (frame_queue_nb_remaining(&is->subpq) > 1) + sp2 = frame_queue_peek_next(&is->subpq); else sp2 = NULL; @@ -1449,16 +1669,7 @@ retry: || (is->vidclk.pts > (sp->pts + ((float) sp->sub.end_display_time / 1000))) || (sp2 && is->vidclk.pts > (sp2->pts + ((float) sp2->sub.start_display_time / 1000)))) { - free_subpicture(sp); - - /* update queue size and signal for next picture */ - if (++is->subpq_rindex == SUBPICTURE_QUEUE_SIZE) - is->subpq_rindex = 0; - - SDL_LockMutex(is->subpq_mutex); - is->subpq_size--; - SDL_CondSignal(is->subpq_cond); - SDL_UnlockMutex(is->subpq_mutex); + frame_queue_next(&is->subpq); } else { break; } @@ -1470,7 +1681,7 @@ display: if (!display_disable && is->show_mode == SHOW_MODE_VIDEO) video_display(is); - pictq_next_picture(is); + frame_queue_next(&is->pictq); if (is->step && !is->paused) stream_toggle_pause(is); @@ -1522,10 +1733,10 @@ display: potential locking problems */ static void alloc_picture(VideoState *is) { - VideoPicture *vp; + Frame *vp; int64_t bufferdiff; - vp = &is->pictq[is->pictq_windex]; + vp = &is->pictq.queue[is->pictq.windex]; free_picture(vp); @@ -1545,10 +1756,10 @@ static void alloc_picture(VideoState *is) do_exit(is); } - SDL_LockMutex(is->pictq_mutex); + SDL_LockMutex(is->pictq.mutex); vp->allocated = 1; - SDL_CondSignal(is->pictq_cond); - SDL_UnlockMutex(is->pictq_mutex); + SDL_CondSignal(is->pictq.cond); + SDL_UnlockMutex(is->pictq.mutex); } static void duplicate_right_border_pixels(SDL_Overlay *bmp) { @@ -1571,27 +1782,16 @@ static void duplicate_right_border_pixels(SDL_Overlay *bmp) { static int queue_picture(VideoState *is, AVFrame *src_frame, double pts, double duration, int64_t pos, int serial) { - VideoPicture *vp; + Frame *vp; #if defined(DEBUG_SYNC) && 0 printf("frame_type=%c pts=%0.3f\n", av_get_picture_type_char(src_frame->pict_type), pts); #endif - /* wait until we have space to put a new picture */ - SDL_LockMutex(is->pictq_mutex); - - while (is->pictq_size >= VIDEO_PICTURE_QUEUE_SIZE && - !is->videoq.abort_request) { - SDL_CondWait(is->pictq_cond, is->pictq_mutex); - } - SDL_UnlockMutex(is->pictq_mutex); - - if (is->videoq.abort_request) + if (!(vp = frame_queue_peek_writable(&is->pictq))) return -1; - vp = &is->pictq[is->pictq_windex]; - vp->sar = src_frame->sample_aspect_ratio; /* alloc or resize hardware picture buffer */ @@ -1612,17 +1812,17 @@ static int queue_picture(VideoState *is, AVFrame *src_frame, double pts, double SDL_PushEvent(&event); /* wait until the picture is allocated */ - SDL_LockMutex(is->pictq_mutex); + SDL_LockMutex(is->pictq.mutex); while (!vp->allocated && !is->videoq.abort_request) { - SDL_CondWait(is->pictq_cond, is->pictq_mutex); + SDL_CondWait(is->pictq.cond, is->pictq.mutex); } /* if the queue is aborted, we have to pop the pending ALLOC event or wait for the allocation to complete */ if (is->videoq.abort_request && SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_EVENTMASK(FF_ALLOC_EVENT)) != 1) { while (!vp->allocated && !is->abort_request) { - SDL_CondWait(is->pictq_cond, is->pictq_mutex); + SDL_CondWait(is->pictq.cond, is->pictq.mutex); } } - SDL_UnlockMutex(is->pictq_mutex); + SDL_UnlockMutex(is->pictq.mutex); if (is->videoq.abort_request) return -1; @@ -1670,45 +1870,21 @@ static int queue_picture(VideoState *is, AVFrame *src_frame, double pts, double vp->serial = serial; /* now we can update the picture count */ - if (++is->pictq_windex == VIDEO_PICTURE_QUEUE_SIZE) - is->pictq_windex = 0; - SDL_LockMutex(is->pictq_mutex); - is->pictq_size++; - SDL_UnlockMutex(is->pictq_mutex); + frame_queue_push(&is->pictq); } return 0; } -static int get_video_frame(VideoState *is, AVFrame *frame, AVPacket *pkt, int *serial) +static int get_video_frame(VideoState *is, AVFrame *frame) { int got_picture; - if (packet_queue_get(&is->videoq, pkt, 1, serial) < 0) + if ((got_picture = decoder_decode_frame(&is->viddec, frame, NULL)) < 0) return -1; - if (pkt->data == flush_pkt.data) { - avcodec_flush_buffers(is->video_st->codec); - return 0; - } - - if(avcodec_decode_video2(is->video_st->codec, frame, &got_picture, pkt) < 0) - return 0; - - if (!got_picture && !pkt->data) - is->video_finished = *serial; - if (got_picture) { - int ret = 1; double dpts = NAN; - if (decoder_reorder_pts == -1) { - frame->pts = av_frame_get_best_effort_timestamp(frame); - } else if (decoder_reorder_pts) { - frame->pts = frame->pkt_pts; - } else { - frame->pts = frame->pkt_dts; - } - if (frame->pts != AV_NOPTS_VALUE) dpts = av_q2d(is->video_st->time_base) * frame->pts; @@ -1719,18 +1895,17 @@ static int get_video_frame(VideoState *is, AVFrame *frame, AVPacket *pkt, int *s double diff = dpts - get_master_clock(is); if (!isnan(diff) && fabs(diff) < AV_NOSYNC_THRESHOLD && diff - is->frame_last_filter_delay < 0 && - *serial == is->vidclk.serial && + is->viddec.pkt_serial == is->vidclk.serial && is->videoq.nb_packets) { is->frame_drops_early++; av_frame_unref(frame); - ret = 0; + got_picture = 0; } } } - - return ret; } - return 0; + + return got_picture; } #if CONFIG_AVFILTER @@ -1943,15 +2118,100 @@ end: } #endif /* CONFIG_AVFILTER */ +static int audio_thread(void *arg) +{ + VideoState *is = arg; + AVFrame *frame = av_frame_alloc(); + Frame *af; +#if CONFIG_AVFILTER + int last_serial = -1; + int64_t dec_channel_layout; + int reconfigure; +#endif + int got_frame = 0; + AVRational tb; + int ret = 0; + + if (!frame) + return AVERROR(ENOMEM); + + do { + if ((got_frame = decoder_decode_frame(&is->auddec, frame, NULL)) < 0) + goto the_end; + + if (got_frame) { + tb = (AVRational){1, frame->sample_rate}; + +#if CONFIG_AVFILTER + dec_channel_layout = get_valid_channel_layout(frame->channel_layout, av_frame_get_channels(frame)); + + reconfigure = + cmp_audio_fmts(is->audio_filter_src.fmt, is->audio_filter_src.channels, + frame->format, av_frame_get_channels(frame)) || + is->audio_filter_src.channel_layout != dec_channel_layout || + is->audio_filter_src.freq != frame->sample_rate || + is->auddec.pkt_serial != last_serial; + + if (reconfigure) { + char buf1[1024], buf2[1024]; + av_get_channel_layout_string(buf1, sizeof(buf1), -1, is->audio_filter_src.channel_layout); + av_get_channel_layout_string(buf2, sizeof(buf2), -1, dec_channel_layout); + av_log(NULL, AV_LOG_DEBUG, + "Audio frame changed from rate:%d ch:%d fmt:%s layout:%s serial:%d to rate:%d ch:%d fmt:%s layout:%s serial:%d\n", + is->audio_filter_src.freq, is->audio_filter_src.channels, av_get_sample_fmt_name(is->audio_filter_src.fmt), buf1, last_serial, + frame->sample_rate, av_frame_get_channels(frame), av_get_sample_fmt_name(frame->format), buf2, is->auddec.pkt_serial); + + is->audio_filter_src.fmt = frame->format; + is->audio_filter_src.channels = av_frame_get_channels(frame); + is->audio_filter_src.channel_layout = dec_channel_layout; + is->audio_filter_src.freq = frame->sample_rate; + last_serial = is->auddec.pkt_serial; + + if ((ret = configure_audio_filters(is, afilters, 1)) < 0) + goto the_end; + } + + if ((ret = av_buffersrc_add_frame(is->in_audio_filter, frame)) < 0) + goto the_end; + + while ((ret = av_buffersink_get_frame_flags(is->out_audio_filter, frame, 0)) >= 0) { + tb = is->out_audio_filter->inputs[0]->time_base; +#endif + if (!(af = frame_queue_peek_writable(&is->sampq))) + goto the_end; + + af->pts = (frame->pts == AV_NOPTS_VALUE) ? NAN : frame->pts * av_q2d(tb); + af->pos = av_frame_get_pkt_pos(frame); + af->serial = is->auddec.pkt_serial; + af->duration = av_q2d((AVRational){frame->nb_samples, frame->sample_rate}); + + av_frame_move_ref(af->frame, frame); + frame_queue_push(&is->sampq); + +#if CONFIG_AVFILTER + if (is->audioq.serial != is->auddec.pkt_serial) + break; + } + if (ret == AVERROR_EOF) + is->auddec.finished = is->auddec.pkt_serial; +#endif + } + } while (ret >= 0 || ret == AVERROR(EAGAIN) || ret == AVERROR_EOF); + the_end: +#if CONFIG_AVFILTER + avfilter_graph_free(&is->agraph); +#endif + av_frame_free(&frame); + return ret; +} + static int video_thread(void *arg) { - AVPacket pkt = { 0 }; VideoState *is = arg; AVFrame *frame = av_frame_alloc(); double pts; double duration; int ret; - int serial = 0; AVRational tb = is->video_st->time_base; AVRational frame_rate = av_guess_frame_rate(is->ic, is->video_st, NULL); @@ -1966,12 +2226,7 @@ static int video_thread(void *arg) #endif for (;;) { - while (is->paused && !is->videoq.abort_request) - SDL_Delay(10); - - av_free_packet(&pkt); - - ret = get_video_frame(is, frame, &pkt, &serial); + ret = get_video_frame(is, frame); if (ret < 0) goto the_end; if (!ret) @@ -1981,14 +2236,14 @@ static int video_thread(void *arg) if ( last_w != frame->width || last_h != frame->height || last_format != frame->format - || last_serial != serial + || last_serial != is->viddec.pkt_serial || last_vfilter_idx != is->vfilter_idx) { av_log(NULL, AV_LOG_DEBUG, "Video frame changed from size:%dx%d format:%s serial:%d to size:%dx%d format:%s serial:%d\n", last_w, last_h, (const char *)av_x_if_null(av_get_pix_fmt_name(last_format), "none"), last_serial, frame->width, frame->height, - (const char *)av_x_if_null(av_get_pix_fmt_name(frame->format), "none"), serial); + (const char *)av_x_if_null(av_get_pix_fmt_name(frame->format), "none"), is->viddec.pkt_serial); avfilter_graph_free(&graph); graph = avfilter_graph_alloc(); if ((ret = configure_video_filters(graph, is, vfilters_list ? vfilters_list[is->vfilter_idx] : NULL, frame)) < 0) { @@ -2003,7 +2258,7 @@ static int video_thread(void *arg) last_w = frame->width; last_h = frame->height; last_format = frame->format; - last_serial = serial; + last_serial = is->viddec.pkt_serial; last_vfilter_idx = is->vfilter_idx; frame_rate = filt_out->inputs[0]->frame_rate; } @@ -2018,7 +2273,7 @@ static int video_thread(void *arg) ret = av_buffersink_get_frame_flags(filt_out, frame, 0); if (ret < 0) { if (ret == AVERROR_EOF) - is->video_finished = serial; + is->viddec.finished = is->viddec.pkt_serial; ret = 0; break; } @@ -2030,7 +2285,7 @@ static int video_thread(void *arg) #endif duration = (frame_rate.num && frame_rate.den ? av_q2d((AVRational){frame_rate.den, frame_rate.num}) : 0); pts = (frame->pts == AV_NOPTS_VALUE) ? NAN : frame->pts * av_q2d(tb); - ret = queue_picture(is, frame, pts, duration, av_frame_get_pkt_pos(frame), serial); + ret = queue_picture(is, frame, pts, duration, av_frame_get_pkt_pos(frame), is->viddec.pkt_serial); av_frame_unref(frame); #if CONFIG_AVFILTER } @@ -2043,7 +2298,6 @@ static int video_thread(void *arg) #if CONFIG_AVFILTER avfilter_graph_free(&graph); #endif - av_free_packet(&pkt); av_frame_free(&frame); return 0; } @@ -2051,50 +2305,26 @@ static int video_thread(void *arg) static int subtitle_thread(void *arg) { VideoState *is = arg; - SubPicture *sp; - AVPacket pkt1, *pkt = &pkt1; + Frame *sp; int got_subtitle; - int serial; double pts; int i, j; int r, g, b, y, u, v, a; for (;;) { - while (is->paused && !is->subtitleq.abort_request) { - SDL_Delay(10); - } - if (packet_queue_get(&is->subtitleq, pkt, 1, &serial) < 0) - break; - - if (pkt->data == flush_pkt.data) { - avcodec_flush_buffers(is->subtitle_st->codec); - continue; - } - SDL_LockMutex(is->subpq_mutex); - while (is->subpq_size >= SUBPICTURE_QUEUE_SIZE && - !is->subtitleq.abort_request) { - SDL_CondWait(is->subpq_cond, is->subpq_mutex); - } - SDL_UnlockMutex(is->subpq_mutex); - - if (is->subtitleq.abort_request) + if (!(sp = frame_queue_peek_writable(&is->subpq))) return 0; - sp = &is->subpq[is->subpq_windex]; + if ((got_subtitle = decoder_decode_frame(&is->subdec, NULL, &sp->sub)) < 0) + break; - /* NOTE: ipts is the PTS of the _first_ picture beginning in - this packet, if any */ pts = 0; - if (pkt->pts != AV_NOPTS_VALUE) - pts = av_q2d(is->subtitle_st->time_base) * pkt->pts; - avcodec_decode_subtitle2(is->subtitle_st->codec, &sp->sub, - &got_subtitle, pkt); if (got_subtitle && sp->sub.format == 0) { if (sp->sub.pts != AV_NOPTS_VALUE) pts = sp->sub.pts / (double)AV_TIME_BASE; sp->pts = pts; - sp->serial = serial; + sp->serial = is->subdec.pkt_serial; for (i = 0; i < sp->sub.num_rects; i++) { @@ -2109,15 +2339,10 @@ static int subtitle_thread(void *arg) } /* now we can update the picture count */ - if (++is->subpq_windex == SUBPICTURE_QUEUE_SIZE) - is->subpq_windex = 0; - SDL_LockMutex(is->subpq_mutex); - is->subpq_size++; - SDL_UnlockMutex(is->subpq_mutex); + frame_queue_push(&is->subpq); } else if (got_subtitle) { avsubtitle_free(&sp->sub); } - av_free_packet(pkt); } return 0; } @@ -2193,229 +2418,107 @@ static int synchronize_audio(VideoState *is, int nb_samples) */ static int audio_decode_frame(VideoState *is) { - AVPacket *pkt_temp = &is->audio_pkt_temp; - AVPacket *pkt = &is->audio_pkt; - AVCodecContext *dec = is->audio_st->codec; - int len1, data_size, resampled_data_size; + int data_size, resampled_data_size; int64_t dec_channel_layout; - int got_frame; av_unused double audio_clock0; int wanted_nb_samples; - AVRational tb; - int ret; - int reconfigure; + Frame *af; - for (;;) { - /* NOTE: the audio packet can contain several frames */ - while (pkt_temp->stream_index != -1 || is->audio_buf_frames_pending) { - if (!is->frame) { - if (!(is->frame = av_frame_alloc())) - return AVERROR(ENOMEM); - } else { - av_frame_unref(is->frame); - } + if (is->paused) + return -1; - if (is->audioq.serial != is->audio_pkt_temp_serial) - break; + do { + if (!(af = frame_queue_peek_readable(&is->sampq))) + return -1; + frame_queue_next(&is->sampq); + } while (af->serial != is->audioq.serial); + + data_size = av_samples_get_buffer_size(NULL, av_frame_get_channels(af->frame), + af->frame->nb_samples, + af->frame->format, 1); + + dec_channel_layout = + (af->frame->channel_layout && av_frame_get_channels(af->frame) == av_get_channel_layout_nb_channels(af->frame->channel_layout)) ? + af->frame->channel_layout : av_get_default_channel_layout(av_frame_get_channels(af->frame)); + wanted_nb_samples = synchronize_audio(is, af->frame->nb_samples); + + if (af->frame->format != is->audio_src.fmt || + dec_channel_layout != is->audio_src.channel_layout || + af->frame->sample_rate != is->audio_src.freq || + (wanted_nb_samples != af->frame->nb_samples && !is->swr_ctx)) { + swr_free(&is->swr_ctx); + is->swr_ctx = swr_alloc_set_opts(NULL, + is->audio_tgt.channel_layout, is->audio_tgt.fmt, is->audio_tgt.freq, + dec_channel_layout, af->frame->format, af->frame->sample_rate, + 0, NULL); + if (!is->swr_ctx || swr_init(is->swr_ctx) < 0) { + av_log(NULL, AV_LOG_ERROR, + "Cannot create sample rate converter for conversion of %d Hz %s %d channels to %d Hz %s %d channels!\n", + af->frame->sample_rate, av_get_sample_fmt_name(af->frame->format), av_frame_get_channels(af->frame), + is->audio_tgt.freq, av_get_sample_fmt_name(is->audio_tgt.fmt), is->audio_tgt.channels); + swr_free(&is->swr_ctx); + return -1; + } + is->audio_src.channel_layout = dec_channel_layout; + is->audio_src.channels = av_frame_get_channels(af->frame); + is->audio_src.freq = af->frame->sample_rate; + is->audio_src.fmt = af->frame->format; + } - if (is->paused) + if (is->swr_ctx) { + const uint8_t **in = (const uint8_t **)af->frame->extended_data; + uint8_t **out = &is->audio_buf1; + int out_count = (int64_t)wanted_nb_samples * is->audio_tgt.freq / af->frame->sample_rate + 256; + int out_size = av_samples_get_buffer_size(NULL, is->audio_tgt.channels, out_count, is->audio_tgt.fmt, 0); + int len2; + if (out_size < 0) { + av_log(NULL, AV_LOG_ERROR, "av_samples_get_buffer_size() failed\n"); + return -1; + } + if (wanted_nb_samples != af->frame->nb_samples) { + if (swr_set_compensation(is->swr_ctx, (wanted_nb_samples - af->frame->nb_samples) * is->audio_tgt.freq / af->frame->sample_rate, + wanted_nb_samples * is->audio_tgt.freq / af->frame->sample_rate) < 0) { + av_log(NULL, AV_LOG_ERROR, "swr_set_compensation() failed\n"); return -1; - - if (!is->audio_buf_frames_pending) { - len1 = avcodec_decode_audio4(dec, is->frame, &got_frame, pkt_temp); - if (len1 < 0) { - /* if error, we skip the frame */ - pkt_temp->size = 0; - break; - } - - pkt_temp->dts = - pkt_temp->pts = AV_NOPTS_VALUE; - pkt_temp->data += len1; - pkt_temp->size -= len1; - if (pkt_temp->data && pkt_temp->size <= 0 || !pkt_temp->data && !got_frame) - pkt_temp->stream_index = -1; - if (!pkt_temp->data && !got_frame) - is->audio_finished = is->audio_pkt_temp_serial; - - if (!got_frame) - continue; - - tb = (AVRational){1, is->frame->sample_rate}; - if (is->frame->pts != AV_NOPTS_VALUE) - is->frame->pts = av_rescale_q(is->frame->pts, dec->time_base, tb); - else if (is->frame->pkt_pts != AV_NOPTS_VALUE) - is->frame->pts = av_rescale_q(is->frame->pkt_pts, is->audio_st->time_base, tb); - else if (is->audio_frame_next_pts != AV_NOPTS_VALUE) -#if CONFIG_AVFILTER - is->frame->pts = av_rescale_q(is->audio_frame_next_pts, (AVRational){1, is->audio_filter_src.freq}, tb); -#else - is->frame->pts = av_rescale_q(is->audio_frame_next_pts, (AVRational){1, is->audio_src.freq}, tb); -#endif - - if (is->frame->pts != AV_NOPTS_VALUE) - is->audio_frame_next_pts = is->frame->pts + is->frame->nb_samples; - -#if CONFIG_AVFILTER - dec_channel_layout = get_valid_channel_layout(is->frame->channel_layout, av_frame_get_channels(is->frame)); - - reconfigure = - cmp_audio_fmts(is->audio_filter_src.fmt, is->audio_filter_src.channels, - is->frame->format, av_frame_get_channels(is->frame)) || - is->audio_filter_src.channel_layout != dec_channel_layout || - is->audio_filter_src.freq != is->frame->sample_rate || - is->audio_pkt_temp_serial != is->audio_last_serial; - - if (reconfigure) { - char buf1[1024], buf2[1024]; - av_get_channel_layout_string(buf1, sizeof(buf1), -1, is->audio_filter_src.channel_layout); - av_get_channel_layout_string(buf2, sizeof(buf2), -1, dec_channel_layout); - av_log(NULL, AV_LOG_DEBUG, - "Audio frame changed from rate:%d ch:%d fmt:%s layout:%s serial:%d to rate:%d ch:%d fmt:%s layout:%s serial:%d\n", - is->audio_filter_src.freq, is->audio_filter_src.channels, av_get_sample_fmt_name(is->audio_filter_src.fmt), buf1, is->audio_last_serial, - is->frame->sample_rate, av_frame_get_channels(is->frame), av_get_sample_fmt_name(is->frame->format), buf2, is->audio_pkt_temp_serial); - - is->audio_filter_src.fmt = is->frame->format; - is->audio_filter_src.channels = av_frame_get_channels(is->frame); - is->audio_filter_src.channel_layout = dec_channel_layout; - is->audio_filter_src.freq = is->frame->sample_rate; - is->audio_last_serial = is->audio_pkt_temp_serial; - - if ((ret = configure_audio_filters(is, afilters, 1)) < 0) - return ret; - } - - if ((ret = av_buffersrc_add_frame(is->in_audio_filter, is->frame)) < 0) - return ret; -#endif - } -#if CONFIG_AVFILTER - if ((ret = av_buffersink_get_frame_flags(is->out_audio_filter, is->frame, 0)) < 0) { - if (ret == AVERROR(EAGAIN)) { - is->audio_buf_frames_pending = 0; - continue; - } - if (ret == AVERROR_EOF) - is->audio_finished = is->audio_pkt_temp_serial; - return ret; } - is->audio_buf_frames_pending = 1; - tb = is->out_audio_filter->inputs[0]->time_base; -#endif - - data_size = av_samples_get_buffer_size(NULL, av_frame_get_channels(is->frame), - is->frame->nb_samples, - is->frame->format, 1); - - dec_channel_layout = - (is->frame->channel_layout && av_frame_get_channels(is->frame) == av_get_channel_layout_nb_channels(is->frame->channel_layout)) ? - is->frame->channel_layout : av_get_default_channel_layout(av_frame_get_channels(is->frame)); - wanted_nb_samples = synchronize_audio(is, is->frame->nb_samples); - - if (is->frame->format != is->audio_src.fmt || - dec_channel_layout != is->audio_src.channel_layout || - is->frame->sample_rate != is->audio_src.freq || - (wanted_nb_samples != is->frame->nb_samples && !is->swr_ctx)) { - swr_free(&is->swr_ctx); - is->swr_ctx = swr_alloc_set_opts(NULL, - is->audio_tgt.channel_layout, is->audio_tgt.fmt, is->audio_tgt.freq, - dec_channel_layout, is->frame->format, is->frame->sample_rate, - 0, NULL); - if (!is->swr_ctx || swr_init(is->swr_ctx) < 0) { - av_log(NULL, AV_LOG_ERROR, - "Cannot create sample rate converter for conversion of %d Hz %s %d channels to %d Hz %s %d channels!\n", - is->frame->sample_rate, av_get_sample_fmt_name(is->frame->format), av_frame_get_channels(is->frame), - is->audio_tgt.freq, av_get_sample_fmt_name(is->audio_tgt.fmt), is->audio_tgt.channels); - break; - } - is->audio_src.channel_layout = dec_channel_layout; - is->audio_src.channels = av_frame_get_channels(is->frame); - is->audio_src.freq = is->frame->sample_rate; - is->audio_src.fmt = is->frame->format; - } - - if (is->swr_ctx) { - const uint8_t **in = (const uint8_t **)is->frame->extended_data; - uint8_t **out = &is->audio_buf1; - int out_count = (int64_t)wanted_nb_samples * is->audio_tgt.freq / is->frame->sample_rate + 256; - int out_size = av_samples_get_buffer_size(NULL, is->audio_tgt.channels, out_count, is->audio_tgt.fmt, 0); - int len2; - if (out_size < 0) { - av_log(NULL, AV_LOG_ERROR, "av_samples_get_buffer_size() failed\n"); - break; - } - if (wanted_nb_samples != is->frame->nb_samples) { - if (swr_set_compensation(is->swr_ctx, (wanted_nb_samples - is->frame->nb_samples) * is->audio_tgt.freq / is->frame->sample_rate, - wanted_nb_samples * is->audio_tgt.freq / is->frame->sample_rate) < 0) { - av_log(NULL, AV_LOG_ERROR, "swr_set_compensation() failed\n"); - break; - } - } - av_fast_malloc(&is->audio_buf1, &is->audio_buf1_size, out_size); - if (!is->audio_buf1) - return AVERROR(ENOMEM); - len2 = swr_convert(is->swr_ctx, out, out_count, in, is->frame->nb_samples); - if (len2 < 0) { - av_log(NULL, AV_LOG_ERROR, "swr_convert() failed\n"); - break; - } - if (len2 == out_count) { - av_log(NULL, AV_LOG_WARNING, "audio buffer is probably too small\n"); - swr_init(is->swr_ctx); - } - is->audio_buf = is->audio_buf1; - resampled_data_size = len2 * is->audio_tgt.channels * av_get_bytes_per_sample(is->audio_tgt.fmt); - } else { - is->audio_buf = is->frame->data[0]; - resampled_data_size = data_size; - } - - audio_clock0 = is->audio_clock; - /* update the audio clock with the pts */ - if (is->frame->pts != AV_NOPTS_VALUE) - is->audio_clock = is->frame->pts * av_q2d(tb) + (double) is->frame->nb_samples / is->frame->sample_rate; - else - is->audio_clock = NAN; - is->audio_clock_serial = is->audio_pkt_temp_serial; -#ifdef DEBUG - { - static double last_clock; - printf("audio: delay=%0.3f clock=%0.3f clock0=%0.3f\n", - is->audio_clock - last_clock, - is->audio_clock, audio_clock0); - last_clock = is->audio_clock; - } -#endif - return resampled_data_size; } - - /* free the current packet */ - if (pkt->data) - av_free_packet(pkt); - memset(pkt_temp, 0, sizeof(*pkt_temp)); - pkt_temp->stream_index = -1; - - if (is->audioq.abort_request) { + av_fast_malloc(&is->audio_buf1, &is->audio_buf1_size, out_size); + if (!is->audio_buf1) + return AVERROR(ENOMEM); + len2 = swr_convert(is->swr_ctx, out, out_count, in, af->frame->nb_samples); + if (len2 < 0) { + av_log(NULL, AV_LOG_ERROR, "swr_convert() failed\n"); return -1; } - - if (is->audioq.nb_packets == 0) - SDL_CondSignal(is->continue_read_thread); - - /* read next packet */ - if ((packet_queue_get(&is->audioq, pkt, 1, &is->audio_pkt_temp_serial)) < 0) - return -1; - - if (pkt->data == flush_pkt.data) { - avcodec_flush_buffers(dec); - is->audio_buf_frames_pending = 0; - is->audio_frame_next_pts = AV_NOPTS_VALUE; - if ((is->ic->iformat->flags & (AVFMT_NOBINSEARCH | AVFMT_NOGENSEARCH | AVFMT_NO_BYTE_SEEK)) && !is->ic->iformat->read_seek) - is->audio_frame_next_pts = is->audio_st->start_time; + if (len2 == out_count) { + av_log(NULL, AV_LOG_WARNING, "audio buffer is probably too small\n"); + if (swr_init(is->swr_ctx) < 0) + swr_free(&is->swr_ctx); } + is->audio_buf = is->audio_buf1; + resampled_data_size = len2 * is->audio_tgt.channels * av_get_bytes_per_sample(is->audio_tgt.fmt); + } else { + is->audio_buf = af->frame->data[0]; + resampled_data_size = data_size; + } - *pkt_temp = *pkt; + audio_clock0 = is->audio_clock; + /* update the audio clock with the pts */ + if (!isnan(af->pts)) + is->audio_clock = af->pts + (double) af->frame->nb_samples / af->frame->sample_rate; + else + is->audio_clock = NAN; + is->audio_clock_serial = af->serial; +#ifdef DEBUG + { + static double last_clock; + printf("audio: delay=%0.3f clock=%0.3f clock0=%0.3f\n", + is->audio_clock - last_clock, + is->audio_clock, audio_clock0); + last_clock = is->audio_clock; } +#endif + return resampled_data_size; } /* prepare a new audio buffer */ @@ -2540,7 +2643,7 @@ static int stream_component_open(VideoState *is, int stream_index) AVDictionaryEntry *t = NULL; int sample_rate, nb_channels; int64_t channel_layout; - int ret; + int ret = 0; int stream_lowres = lowres; if (stream_index < 0 || stream_index >= ic->nb_streams) @@ -2565,7 +2668,6 @@ static int stream_component_open(VideoState *is, int stream_index) } avctx->codec_id = codec->id; - avctx->workaround_bugs = workaround_bugs; if(stream_lowres > av_codec_get_max_lowres(codec)){ av_log(avctx, AV_LOG_WARNING, "The maximum value for lowres supported by the decoder is %d\n", av_codec_get_max_lowres(codec)); @@ -2585,11 +2687,13 @@ static int stream_component_open(VideoState *is, int stream_index) av_dict_set_int(&opts, "lowres", stream_lowres, 0); if (avctx->codec_type == AVMEDIA_TYPE_VIDEO || avctx->codec_type == AVMEDIA_TYPE_AUDIO) av_dict_set(&opts, "refcounted_frames", "1", 0); - if (avcodec_open2(avctx, codec, &opts) < 0) - return -1; + if ((ret = avcodec_open2(avctx, codec, &opts)) < 0) { + goto fail; + } if ((t = av_dict_get(opts, "", NULL, AV_DICT_IGNORE_SUFFIX))) { av_log(NULL, AV_LOG_ERROR, "Option %s not found.\n", t->key); - return AVERROR_OPTION_NOT_FOUND; + ret = AVERROR_OPTION_NOT_FOUND; + goto fail; } ic->streams[stream_index]->discard = AVDISCARD_DEFAULT; @@ -2604,7 +2708,7 @@ static int stream_component_open(VideoState *is, int stream_index) is->audio_filter_src.channel_layout = get_valid_channel_layout(avctx->channel_layout, avctx->channels); is->audio_filter_src.fmt = avctx->sample_fmt; if ((ret = configure_audio_filters(is, afilters, 0)) < 0) - return ret; + goto fail; link = is->out_audio_filter->inputs[0]; sample_rate = link->sample_rate; nb_channels = link->channels; @@ -2618,7 +2722,7 @@ static int stream_component_open(VideoState *is, int stream_index) /* prepare audio output */ if ((ret = audio_open(is, channel_layout, nb_channels, sample_rate, &is->audio_tgt)) < 0) - return ret; + goto fail; is->audio_hw_buf_size = ret; is->audio_src = is->audio_tgt; is->audio_buf_size = 0; @@ -2631,14 +2735,16 @@ static int stream_component_open(VideoState *is, int stream_index) we correct audio sync only if larger than this threshold */ is->audio_diff_threshold = (double)(is->audio_hw_buf_size) / is->audio_tgt.bytes_per_sec; - memset(&is->audio_pkt, 0, sizeof(is->audio_pkt)); - memset(&is->audio_pkt_temp, 0, sizeof(is->audio_pkt_temp)); - is->audio_pkt_temp.stream_index = -1; - is->audio_stream = stream_index; is->audio_st = ic->streams[stream_index]; packet_queue_start(&is->audioq); + decoder_init(&is->auddec, avctx, &is->audioq, is->continue_read_thread); + if ((is->ic->iformat->flags & (AVFMT_NOBINSEARCH | AVFMT_NOGENSEARCH | AVFMT_NO_BYTE_SEEK)) && !is->ic->iformat->read_seek) { + is->auddec.start_pts = is->audio_st->start_time; + is->auddec.start_pts_tb = is->audio_st->time_base; + } + is->audio_tid = SDL_CreateThread(audio_thread, is); SDL_PauseAudio(0); break; case AVMEDIA_TYPE_VIDEO: @@ -2646,20 +2752,26 @@ static int stream_component_open(VideoState *is, int stream_index) is->video_st = ic->streams[stream_index]; packet_queue_start(&is->videoq); + decoder_init(&is->viddec, avctx, &is->videoq, is->continue_read_thread); is->video_tid = SDL_CreateThread(video_thread, is); is->queue_attachments_req = 1; break; case AVMEDIA_TYPE_SUBTITLE: is->subtitle_stream = stream_index; is->subtitle_st = ic->streams[stream_index]; - packet_queue_start(&is->subtitleq); + packet_queue_start(&is->subtitleq); + decoder_init(&is->subdec, avctx, &is->subtitleq, is->continue_read_thread); is->subtitle_tid = SDL_CreateThread(subtitle_thread, is); break; default: break; } - return 0; + +fail: + av_dict_free(&opts); + + return ret; } static void stream_component_close(VideoState *is, int stream_index) @@ -2674,16 +2786,16 @@ static void stream_component_close(VideoState *is, int stream_index) switch (avctx->codec_type) { case AVMEDIA_TYPE_AUDIO: packet_queue_abort(&is->audioq); - + frame_queue_signal(&is->sampq); SDL_CloseAudio(); + SDL_WaitThread(is->audio_tid, NULL); + decoder_destroy(&is->auddec); packet_queue_flush(&is->audioq); - av_free_packet(&is->audio_pkt); swr_free(&is->swr_ctx); av_freep(&is->audio_buf1); is->audio_buf1_size = 0; is->audio_buf = NULL; - av_frame_free(&is->frame); if (is->rdft) { av_rdft_end(is->rdft); @@ -2691,21 +2803,17 @@ static void stream_component_close(VideoState *is, int stream_index) is->rdft = NULL; is->rdft_bits = 0; } -#if CONFIG_AVFILTER - avfilter_graph_free(&is->agraph); -#endif break; case AVMEDIA_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); + frame_queue_signal(&is->pictq); SDL_WaitThread(is->video_tid, NULL); + decoder_destroy(&is->viddec); packet_queue_flush(&is->videoq); break; case AVMEDIA_TYPE_SUBTITLE: @@ -2713,12 +2821,11 @@ static void stream_component_close(VideoState *is, int stream_index) /* note: we also signal this mutex to make sure we deblock the video thread in all cases */ - SDL_LockMutex(is->subpq_mutex); - SDL_CondSignal(is->subpq_cond); - SDL_UnlockMutex(is->subpq_mutex); + frame_queue_signal(&is->subpq); SDL_WaitThread(is->subtitle_tid, NULL); + decoder_destroy(&is->subdec); packet_queue_flush(&is->subtitleq); break; default: @@ -2782,6 +2889,7 @@ static int read_thread(void *arg) AVDictionary **opts; int orig_nb_streams; SDL_mutex *wait_mutex = SDL_CreateMutex(); + int scan_all_pmts_set = 0; memset(st_index, -1, sizeof(st_index)); is->last_video_stream = is->video_stream = -1; @@ -2791,12 +2899,19 @@ static int read_thread(void *arg) ic = avformat_alloc_context(); ic->interrupt_callback.callback = decode_interrupt_cb; ic->interrupt_callback.opaque = is; + if (!av_dict_get(format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE)) { + av_dict_set(&format_opts, "scan_all_pmts", "1", AV_DICT_DONT_OVERWRITE); + scan_all_pmts_set = 1; + } err = avformat_open_input(&ic, is->filename, is->iformat, &format_opts); if (err < 0) { print_error(is->filename, err); ret = -1; goto fail; } + if (scan_all_pmts_set) + av_dict_set(&format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE); + if ((t = av_dict_get(format_opts, "", NULL, AV_DICT_IGNORE_SUFFIX))) { av_log(NULL, AV_LOG_ERROR, "Option %s not found.\n", t->key); ret = AVERROR_OPTION_NOT_FOUND; @@ -2813,15 +2928,17 @@ static int read_thread(void *arg) orig_nb_streams = ic->nb_streams; err = avformat_find_stream_info(ic, opts); + + for (i = 0; i < orig_nb_streams; i++) + av_dict_free(&opts[i]); + av_freep(&opts); + if (err < 0) { av_log(NULL, AV_LOG_WARNING, "%s: could not find codec parameters\n", is->filename); ret = -1; goto fail; } - for (i = 0; i < orig_nb_streams; i++) - av_dict_free(&opts[i]); - av_freep(&opts); if (ic->pb) ic->pb->eof_reached = 0; // FIXME hack, ffplay maybe should not use avio_feof() to test for the end @@ -2991,8 +3108,8 @@ static int read_thread(void *arg) continue; } if (!is->paused && - (!is->audio_st || is->audio_finished == is->audioq.serial) && - (!is->video_st || (is->video_finished == is->videoq.serial && pictq_nb_remaining(is) == 0))) { + (!is->audio_st || (is->auddec.finished == is->audioq.serial && frame_queue_nb_remaining(&is->sampq) == 0)) && + (!is->video_st || (is->viddec.finished == is->videoq.serial && frame_queue_nb_remaining(&is->pictq) == 0))) { if (loop != 1 && (!loop || --loop)) { stream_seek(is, start_time != AV_NOPTS_VALUE ? start_time : 0, 0, 0); } else if (autoexit) { @@ -3000,27 +3117,25 @@ static int read_thread(void *arg) goto fail; } } - if (eof) { - if (is->video_stream >= 0) - packet_queue_put_nullpacket(&is->videoq, is->video_stream); - if (is->audio_stream >= 0) - packet_queue_put_nullpacket(&is->audioq, is->audio_stream); - if (is->subtitle_stream >= 0) - packet_queue_put_nullpacket(&is->subtitleq, is->subtitle_stream); - SDL_Delay(10); - eof=0; - continue; - } ret = av_read_frame(ic, pkt); if (ret < 0) { - if (ret == AVERROR_EOF || avio_feof(ic->pb)) + if ((ret == AVERROR_EOF || avio_feof(ic->pb)) && !eof) { + if (is->video_stream >= 0) + packet_queue_put_nullpacket(&is->videoq, is->video_stream); + if (is->audio_stream >= 0) + packet_queue_put_nullpacket(&is->audioq, is->audio_stream); + if (is->subtitle_stream >= 0) + packet_queue_put_nullpacket(&is->subtitleq, is->subtitle_stream); eof = 1; + } if (ic->pb && ic->pb->error) break; SDL_LockMutex(wait_mutex); SDL_CondWaitTimeout(is->continue_read_thread, wait_mutex, 10); SDL_UnlockMutex(wait_mutex); continue; + } else { + eof = 0; } /* check if packet is in play range specified by user, then queue, otherwise discard */ stream_start_time = ic->streams[pkt->stream_index]->start_time; @@ -3054,8 +3169,9 @@ static int read_thread(void *arg) stream_component_close(is, is->video_stream); if (is->subtitle_stream >= 0) stream_component_close(is, is->subtitle_stream); - if (is->ic) { - avformat_close_input(&is->ic); + if (ic) { + avformat_close_input(&ic); + is->ic = NULL; } if (ret != 0) { @@ -3082,11 +3198,12 @@ static VideoState *stream_open(const char *filename, AVInputFormat *iformat) 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(); + if (frame_queue_init(&is->pictq, &is->videoq, VIDEO_PICTURE_QUEUE_SIZE, 1) < 0) + goto fail; + if (frame_queue_init(&is->subpq, &is->subtitleq, SUBPICTURE_QUEUE_SIZE, 0) < 0) + goto fail; + if (frame_queue_init(&is->sampq, &is->audioq, SAMPLE_QUEUE_SIZE, 1) < 0) + goto fail; packet_queue_init(&is->videoq); packet_queue_init(&is->audioq); @@ -3098,11 +3215,11 @@ static VideoState *stream_open(const char *filename, AVInputFormat *iformat) init_clock(&is->audclk, &is->audioq.serial); init_clock(&is->extclk, &is->extclk.serial); is->audio_clock_serial = -1; - is->audio_last_serial = -1; is->av_sync_type = av_sync_type; is->read_tid = SDL_CreateThread(read_thread, is); if (!is->read_tid) { - av_free(is); +fail: + stream_close(is); return NULL; } return is; @@ -3193,7 +3310,7 @@ static void toggle_full_screen(VideoState *is) /* OS X needs to reallocate the SDL overlays */ int i; for (i = 0; i < VIDEO_PICTURE_QUEUE_SIZE; i++) - is->pictq[i].reallocate = 1; + is->pictq.queue[i].reallocate = 1; #endif is_full_screen = !is_full_screen; video_open(is, 1, NULL); @@ -3344,11 +3461,12 @@ static void event_loop(VideoState *cur_stream) incr = -60.0; do_seek: if (seek_by_bytes) { - if (cur_stream->video_stream >= 0 && cur_stream->video_current_pos >= 0) { - pos = cur_stream->video_current_pos; - } else if (cur_stream->audio_stream >= 0 && cur_stream->audio_pkt.pos >= 0) { - pos = cur_stream->audio_pkt.pos; - } else + pos = -1; + if (pos < 0 && cur_stream->video_stream >= 0) + pos = frame_queue_last_pos(&cur_stream->pictq); + if (pos < 0 && cur_stream->audio_stream >= 0) + pos = frame_queue_last_pos(&cur_stream->sampq); + if (pos < 0) pos = avio_tell(cur_stream->ic->pb); if (cur_stream->ic->bit_rate) incr *= cur_stream->ic->bit_rate / 8.0; @@ -3418,7 +3536,7 @@ static void event_loop(VideoState *cur_stream) break; case SDL_VIDEORESIZE: screen = SDL_SetVideoMode(FFMIN(16383, event.resize.w), event.resize.h, 0, - SDL_HWSURFACE|SDL_RESIZABLE|SDL_ASYNCBLIT|SDL_HWACCEL); + SDL_HWSURFACE|(is_full_screen?SDL_FULLSCREEN:SDL_RESIZABLE)|SDL_ASYNCBLIT|SDL_HWACCEL); if (!screen) { av_log(NULL, AV_LOG_FATAL, "Failed to set video mode\n"); do_exit(cur_stream); @@ -3566,7 +3684,6 @@ static const OptionDef options[] = { { "f", HAS_ARG, { .func_arg = opt_format }, "force format", "fmt" }, { "pix_fmt", HAS_ARG | OPT_EXPERT | OPT_VIDEO, { .func_arg = opt_frame_pix_fmt }, "set pixel format", "format" }, { "stats", OPT_BOOL | OPT_EXPERT, { &show_status }, "show status", "" }, - { "bug", OPT_INT | HAS_ARG | OPT_EXPERT, { &workaround_bugs }, "workaround bugs", "" }, { "fast", OPT_BOOL | OPT_EXPERT, { &fast }, "non spec compliant optimizations", "" }, { "genpts", OPT_BOOL | OPT_EXPERT, { &genpts }, "generate pts", "" }, { "drp", OPT_INT | HAS_ARG | OPT_EXPERT, { &decoder_reorder_pts }, "let decoder reorder pts 0=off 1=on -1=auto", ""},