+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;
+}
+