ff_ffplay.c 130.9 KB
Newer Older
Z
Zhang Rui 已提交
1 2 3
/*
 * Copyright (c) 2003 Fabrice Bellard
 * Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
 *
 * This file is part of ijkPlayer.
 *
 * ijkPlayer is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * ijkPlayer is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with ijkPlayer; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

#include "ff_ffplay.h"
Z
Zhang Rui 已提交
23

Z
Zhang Rui 已提交
24 25 26 27 28 29 30
/**
 * @file
 * simple media player based on the FFmpeg libraries
 */

#include "config.h"
#include <inttypes.h>
Z
Zhang Rui 已提交
31
#include <math.h>
Z
Zhang Rui 已提交
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
#include <limits.h>
#include <signal.h>
#include <stdint.h>

#include "libavutil/avstring.h"
#include "libavutil/eval.h"
#include "libavutil/mathematics.h"
#include "libavutil/pixdesc.h"
#include "libavutil/imgutils.h"
#include "libavutil/dict.h"
#include "libavutil/parseutils.h"
#include "libavutil/samplefmt.h"
#include "libavutil/avassert.h"
#include "libavutil/time.h"
#include "libavformat/avformat.h"
47 48 49
#if CONFIG_AVDEVICE
#include "libavdevice/avdevice.h"
#endif
Z
Zhang Rui 已提交
50 51 52 53 54 55 56 57 58 59 60 61
#include "libswscale/swscale.h"
#include "libavutil/opt.h"
#include "libavcodec/avfft.h"
#include "libswresample/swresample.h"

#if CONFIG_AVFILTER
# include "libavfilter/avcodec.h"
# include "libavfilter/avfilter.h"
# include "libavfilter/buffersink.h"
# include "libavfilter/buffersrc.h"
#endif

Z
Zhang Rui 已提交
62 63
#include "ijksdl/ijksdl_log.h"
#include "ijkavformat/ijkavformat.h"
64
#include "ff_cmdutils.h"
Z
Zhang Rui 已提交
65
#include "ff_fferror.h"
Z
Zhang Rui 已提交
66 67
#include "ff_ffpipeline.h"
#include "ff_ffpipenode.h"
Z
Zhang Rui 已提交
68
#include "ff_ffplay_debug.h"
Z
Zhang Rui 已提交
69
#include "version.h"
Z
Zhang Rui 已提交
70
#include "ijkmeta.h"
71

72 73 74 75
#ifndef AV_CODEC_FLAG2_FAST
#define AV_CODEC_FLAG2_FAST CODEC_FLAG2_FAST
#endif

76 77 78 79
#ifndef AV_CODEC_CAP_DR1
#define AV_CODEC_CAP_DR1 CODEC_CAP_DR1
#endif

Z
Zhang Rui 已提交
80
// FIXME: 9 work around NDKr8e or gcc4.7 bug
Z
Zhang Rui 已提交
81
// isnan() may not recognize some double NAN, so we test both double and float
82
#if defined(__ANDROID__)
Z
Zhang Rui 已提交
83 84 85 86
#ifdef isnan
#undef isnan
#endif
#define isnan(x) (isnan((double)(x)) || isnanf((float)(x)))
87
#endif
Z
Zhang Rui 已提交
88

Z
Zhang Rui 已提交
89
#if defined(__ANDROID__)
90
#define printf(...) ALOGD(__VA_ARGS__)
Z
Zhang Rui 已提交
91
#endif
92

93 94
#define FFP_IO_STAT_STEP (50 * 1024)

95 96
#define FFP_BUF_MSG_PERIOD (3)

97 98 99
// static const AVOption ffp_context_options[] = ...
#include "ff_ffplay_options.h"

100 101
static AVPacket flush_pkt;

Z
Zhang Rui 已提交
102 103 104 105
#if CONFIG_AVFILTER
// FFP_MERGE: opt_add_vfilter
#endif

Z
Zhang Rui 已提交
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
#if CONFIG_AVFILTER
static inline
int cmp_audio_fmts(enum AVSampleFormat fmt1, int64_t channel_count1,
                   enum AVSampleFormat fmt2, int64_t channel_count2)
{
    /* If channel count == 1, planar and non-planar formats are the same */
    if (channel_count1 == 1 && channel_count2 == 1)
        return av_get_packed_sample_fmt(fmt1) != av_get_packed_sample_fmt(fmt2);
    else
        return channel_count1 != channel_count2 || fmt1 != fmt2;
}

static inline
int64_t get_valid_channel_layout(int64_t channel_layout, int channels)
{
    if (channel_layout && av_get_channel_layout_nb_channels(channel_layout) == channels)
        return channel_layout;
    else
        return 0;
}
#endif
Z
Zhang Rui 已提交
127

128
static void free_picture(Frame *vp);
129 130 131 132 133 134

static int packet_queue_put_private(PacketQueue *q, AVPacket *pkt)
{
    MyAVPacketList *pkt1;

    if (q->abort_request)
Z
Zhang Rui 已提交
135
       return -1;
136

137
#ifdef FFP_MERGE
138
    pkt1 = av_malloc(sizeof(MyAVPacketList));
139 140 141 142 143 144 145 146 147 148 149 150
#else
    pkt1 = q->recycle_pkt;
    if (pkt1) {
        q->recycle_pkt = pkt1->next;
        q->recycle_count++;
    } else {
        q->alloc_count++;
        pkt1 = av_malloc(sizeof(MyAVPacketList));
    }
#ifdef FFP_SHOW_PKT_RECYCLE
    int total_count = q->recycle_count + q->alloc_count;
    if (!(total_count % 50)) {
151
        av_log(ffp, AV_LOG_DEBUG, "pkt-recycle \t%d + \t%d = \t%d\n", q->recycle_count, q->alloc_count, total_count);
152 153 154
    }
#endif
#endif
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
    if (!pkt1)
        return -1;
    pkt1->pkt = *pkt;
    pkt1->next = NULL;
    if (pkt == &flush_pkt)
        q->serial++;
    pkt1->serial = q->serial;

    if (!q->last_pkt)
        q->first_pkt = pkt1;
    else
        q->last_pkt->next = pkt1;
    q->last_pkt = pkt1;
    q->nb_packets++;
    q->size += pkt1->pkt.size + sizeof(*pkt1);
170 171
    if (pkt1->pkt.duration > 0)
        q->duration += pkt1->pkt.duration;
172 173 174 175 176 177 178 179 180 181
    /* XXX: should duplicate packet data in DV case */
    SDL_CondSignal(q->cond);
    return 0;
}

static int packet_queue_put(PacketQueue *q, AVPacket *pkt)
{
    int ret;

    /* duplicate the packet */
B
bbcallen 已提交
182
    if (pkt != &flush_pkt && av_dup_packet(pkt) < 0)
183 184 185 186 187 188
        return -1;

    SDL_LockMutex(q->mutex);
    ret = packet_queue_put_private(q, pkt);
    SDL_UnlockMutex(q->mutex);

B
bbcallen 已提交
189
    if (pkt != &flush_pkt && ret < 0)
190 191 192 193 194
        av_free_packet(pkt);

    return ret;
}

195 196 197 198 199 200 201 202 203 204
static int packet_queue_put_nullpacket(PacketQueue *q, int stream_index)
{
    AVPacket pkt1, *pkt = &pkt1;
    av_init_packet(pkt);
    pkt->data = NULL;
    pkt->size = 0;
    pkt->stream_index = stream_index;
    return packet_queue_put(q, pkt);
}

205
/* packet queue handling */
206
static int packet_queue_init(PacketQueue *q)
207 208 209
{
    memset(q, 0, sizeof(PacketQueue));
    q->mutex = SDL_CreateMutex();
210
    if (!q->mutex) {
211
        av_log(NULL, AV_LOG_FATAL, "SDL_CreateMutex(): %s\n", SDL_GetError());
212 213
        return AVERROR(ENOMEM);
    }
214
    q->cond = SDL_CreateCond();
215
    if (!q->cond) {
216
        av_log(NULL, AV_LOG_FATAL, "SDL_CreateCond(): %s\n", SDL_GetError());
217 218
        return AVERROR(ENOMEM);
    }
219
    q->abort_request = 1;
220
    return 0;
221 222 223 224 225 226 227
}

static void packet_queue_flush(PacketQueue *q)
{
    MyAVPacketList *pkt, *pkt1;

    SDL_LockMutex(q->mutex);
Z
Zhang Rui 已提交
228
    for (pkt = q->first_pkt; pkt; pkt = pkt1) {
229 230
        pkt1 = pkt->next;
        av_free_packet(&pkt->pkt);
231
#ifdef FFP_MERGE
232
        av_freep(&pkt);
233 234 235 236
#else
        pkt->next = q->recycle_pkt;
        q->recycle_pkt = pkt;
#endif
237 238 239 240 241
    }
    q->last_pkt = NULL;
    q->first_pkt = NULL;
    q->nb_packets = 0;
    q->size = 0;
242
    q->duration = 0;
243 244 245 246 247
    SDL_UnlockMutex(q->mutex);
}

static void packet_queue_destroy(PacketQueue *q)
{
248 249
    packet_queue_flush(q);

250 251 252 253 254 255 256 257
    SDL_LockMutex(q->mutex);
    while(q->recycle_pkt) {
        MyAVPacketList *pkt = q->recycle_pkt;
        if (pkt)
            q->recycle_pkt = pkt->next;
        av_freep(&pkt);
    }
    SDL_UnlockMutex(q->mutex);
258 259 260

    SDL_DestroyMutex(q->mutex);
    SDL_DestroyCond(q->cond);
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302
}

static void packet_queue_abort(PacketQueue *q)
{
    SDL_LockMutex(q->mutex);

    q->abort_request = 1;

    SDL_CondSignal(q->cond);

    SDL_UnlockMutex(q->mutex);
}

static void packet_queue_start(PacketQueue *q)
{
    SDL_LockMutex(q->mutex);
    q->abort_request = 0;
    packet_queue_put_private(q, &flush_pkt);
    SDL_UnlockMutex(q->mutex);
}

/* return < 0 if aborted, 0 if no packet and > 0 if packet.  */
static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block, int *serial)
{
    MyAVPacketList *pkt1;
    int ret;

    SDL_LockMutex(q->mutex);

    for (;;) {
        if (q->abort_request) {
            ret = -1;
            break;
        }

        pkt1 = q->first_pkt;
        if (pkt1) {
            q->first_pkt = pkt1->next;
            if (!q->first_pkt)
                q->last_pkt = NULL;
            q->nb_packets--;
            q->size -= pkt1->pkt.size + sizeof(*pkt1);
303 304
            if (pkt1->pkt.duration > 0)
                q->duration -= pkt1->pkt.duration;
305 306 307
            *pkt = pkt1->pkt;
            if (serial)
                *serial = pkt1->serial;
308
#ifdef FFP_MERGE
309
            av_free(pkt1);
310 311 312 313
#else
            pkt1->next = q->recycle_pkt;
            q->recycle_pkt = pkt1;
#endif
314 315 316 317 318 319 320 321 322 323 324 325 326
            ret = 1;
            break;
        } else if (!block) {
            ret = 0;
            break;
        } else {
            SDL_CondWait(q->cond, q->mutex);
        }
    }
    SDL_UnlockMutex(q->mutex);
    return ret;
}

327
static int packet_queue_get_or_buffering(FFPlayer *ffp, PacketQueue *q, AVPacket *pkt, int *serial, int *finished)
328
{
329
    assert(finished);
330 331 332
    if (!ffp->packet_buffering)
        return packet_queue_get(q, pkt, 1, serial);

333 334 335 336 337
    while (1) {
        int new_packet = packet_queue_get(q, pkt, 0, serial);
        if (new_packet < 0)
            return -1;
        else if (new_packet == 0) {
338
            if (q->is_buffer_indicator && !*finished)
339 340 341 342 343 344
                ffp_toggle_buffering(ffp, 1);
            new_packet = packet_queue_get(q, pkt, 1, serial);
            if (new_packet < 0)
                return -1;
        }

345
        if (*finished == *serial) {
B
bbcallen 已提交
346
            av_free_packet(pkt);
B
bbcallen 已提交
347
            continue;
B
bbcallen 已提交
348
        }
349 350 351 352 353 354 355
        else
            break;
    }

    return 1;
}

356 357 358 359 360
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;
361
    d->start_pts = AV_NOPTS_VALUE;
Z
Zhang Rui 已提交
362

Z
Zhang Rui 已提交
363 364 365
    d->first_frame_decoded_time = SDL_GetTickHR();
    d->first_frame_decoded = 0;

Z
Zhang Rui 已提交
366
    SDL_ProfilerReset(&d->decode_profiler, -1);
367 368
}

369
static int decoder_decode_frame(FFPlayer *ffp, Decoder *d, AVFrame *frame, AVSubtitle *sub) {
370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387
    int got_frame = 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_or_buffering(ffp, d->queue, &pkt, &d->pkt_serial, &d->finished) < 0)
                    return -1;
                if (pkt.data == flush_pkt.data) {
                    avcodec_flush_buffers(d->avctx);
                    d->finished = 0;
388 389
                    d->next_pts = d->start_pts;
                    d->next_pts_tb = d->start_pts_tb;
390 391 392 393 394 395 396 397
                }
            } 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) {
398
            case AVMEDIA_TYPE_VIDEO: {
399 400
                ret = avcodec_decode_video2(d->avctx, frame, &got_frame, &d->pkt_temp);
                if (got_frame) {
Z
Zhang Rui 已提交
401
                    ffp->stat.vdps = SDL_SpeedSamplerAdd(&ffp->vdps_sampler, FFP_SHOW_VDPS_AVCODEC, "vdps[avcodec]");
402 403 404 405 406 407 408 409
                    if (ffp->decoder_reorder_pts == -1) {
                        frame->pts = av_frame_get_best_effort_timestamp(frame);
                    } else if (ffp->decoder_reorder_pts) {
                        frame->pts = frame->pkt_pts;
                    } else {
                        frame->pts = frame->pkt_dts;
                    }
                }
410
                }
411 412
                break;
            case AVMEDIA_TYPE_AUDIO:
413 414 415 416 417 418
                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)
419
                        frame->pts = av_rescale_q(frame->pkt_pts, av_codec_get_pkt_timebase(d->avctx), tb);
420 421 422 423 424 425 426
                    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;
                    }
                }
427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460
                break;
            // FFP_MERGE: case AVMEDIA_TYPE_SUBTITLE:
            default:
                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);
}

461 462
static void frame_queue_unref_item(Frame *vp)
{
463 464 465 466 467 468 469 470
#ifdef FFP_MERGE
    int i;
    for (i = 0; i < vp->sub.num_rects; i++) {
        av_freep(&vp->subrects[i]->data[0]);
        av_freep(&vp->subrects[i]);
    }
    av_freep(&vp->subrects);
#endif
471
    av_frame_unref(vp->frame);
Z
Zhang Rui 已提交
472
    SDL_VoutUnrefYUVOverlay(vp->bmp);
473 474 475 476 477 478 479 480 481
#ifdef FFP_MERGE
    avsubtitle_free(&vp->sub);
#endif
}

static int frame_queue_init(FrameQueue *f, PacketQueue *pktq, int max_size, int keep_last)
{
    int i;
    memset(f, 0, sizeof(FrameQueue));
482 483
    if (!(f->mutex = SDL_CreateMutex())) {
        av_log(NULL, AV_LOG_FATAL, "SDL_CreateMutex(): %s\n", SDL_GetError());
484
        return AVERROR(ENOMEM);
485 486 487
    }
    if (!(f->cond = SDL_CreateCond())) {
        av_log(NULL, AV_LOG_FATAL, "SDL_CreateCond(): %s\n", SDL_GetError());
488
        return AVERROR(ENOMEM);
489
    }
490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549
    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];
}

550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565
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];
}

566 567 568 569 570 571
static void frame_queue_push(FrameQueue *f)
{
    if (++f->windex == f->max_size)
        f->windex = 0;
    SDL_LockMutex(f->mutex);
    f->size++;
572
    SDL_CondSignal(f->cond);
573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604
    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;
}

605
/* return last shown position */
Z
Zhang Rui 已提交
606
#ifdef FFP_MERGE
607 608 609 610 611 612 613 614
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;
}
Z
Zhang Rui 已提交
615
#endif
616

617 618 619 620 621 622 623 624 625
static void decoder_abort(Decoder *d, FrameQueue *fq)
{
    packet_queue_abort(d->queue);
    frame_queue_signal(fq);
    SDL_WaitThread(d->decoder_tid, NULL);
    d->decoder_tid = NULL;
    packet_queue_flush(d->queue);
}

Z
Zhang Rui 已提交
626 627 628 629 630 631 632 633
// FFP_MERGE: fill_rectangle
// FFP_MERGE: fill_border
// FFP_MERGE: ALPHA_BLEND
// FFP_MERGE: RGBA_IN
// FFP_MERGE: YUVA_IN
// FFP_MERGE: YUVA_OUT
// FFP_MERGE: BPP
// FFP_MERGE: blend_subrect
634

635
static void free_picture(Frame *vp)
636 637 638 639 640 641 642
{
    if (vp->bmp) {
        SDL_VoutFreeYUVOverlay(vp->bmp);
        vp->bmp = NULL;
    }
}

Z
Zhang Rui 已提交
643 644
// FFP_MERGE: calculate_display_rect
// FFP_MERGE: video_image_display
645

Z
Zhang Rui 已提交
646
static void video_image_display2(FFPlayer *ffp)
647
{
648
    VideoState *is = ffp->is;
649
    Frame *vp;
650

651
    vp = frame_queue_peek(&is->pictq);
652
    if (vp->bmp) {
653
        SDL_VoutDisplayYUVOverlay(ffp->vout, vp->bmp);
Z
Zhang Rui 已提交
654
        ffp->stat.vfps = SDL_SpeedSamplerAdd(&ffp->vfps_sampler, FFP_SHOW_VFPS_FFPLAY, "vfps[ffplay]");
Z
Zhang Rui 已提交
655 656
        if (!ffp->first_video_frame_rendered) {
            ffp->first_video_frame_rendered = 1;
657 658
            ffp_notify_msg1(ffp, FFP_MSG_VIDEO_RENDERING_START);
        }
659 660 661
    }
}

Z
Zhang Rui 已提交
662 663
// FFP_MERGE: compute_mod
// FFP_MERGE: video_audio_display
664

665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719
static void stream_component_close(FFPlayer *ffp, int stream_index)
{
    VideoState *is = ffp->is;
    AVFormatContext *ic = is->ic;
    AVCodecContext *avctx;

    if (stream_index < 0 || stream_index >= ic->nb_streams)
        return;
    avctx = ic->streams[stream_index]->codec;

    switch (avctx->codec_type) {
    case AVMEDIA_TYPE_AUDIO:
        decoder_abort(&is->auddec, &is->sampq);
        SDL_AoutCloseAudio(ffp->aout);

        decoder_destroy(&is->auddec);
        swr_free(&is->swr_ctx);
        av_freep(&is->audio_buf1);
        is->audio_buf1_size = 0;
        is->audio_buf = NULL;

#ifdef FFP_MERGE
        if (is->rdft) {
            av_rdft_end(is->rdft);
            av_freep(&is->rdft_data);
            is->rdft = NULL;
            is->rdft_bits = 0;
        }
#endif
        break;
    case AVMEDIA_TYPE_VIDEO:
        decoder_abort(&is->viddec, &is->pictq);
        decoder_destroy(&is->viddec);
        break;
        // FFP_MERGE: case AVMEDIA_TYPE_SUBTITLE:
    default:
        break;
    }

    ic->streams[stream_index]->discard = AVDISCARD_ALL;
    avcodec_close(avctx);
    switch (avctx->codec_type) {
    case AVMEDIA_TYPE_AUDIO:
        is->audio_st = NULL;
        is->audio_stream = -1;
        break;
    case AVMEDIA_TYPE_VIDEO:
        is->video_st = NULL;
        is->video_stream = -1;
        break;
        // FFP_MERGE: case AVMEDIA_TYPE_SUBTITLE:
    default:
        break;
    }
}
720 721

static void stream_close(FFPlayer *ffp)
722
{
723
    VideoState *is = ffp->is;
724 725
    /* XXX: use a special url_shutdown call to abort parse cleanly */
    is->abort_request = 1;
726 727
    packet_queue_abort(&is->videoq);
    packet_queue_abort(&is->audioq);
728
    av_log(NULL, AV_LOG_DEBUG, "wait for read_tid\n");
729
    SDL_WaitThread(is->read_tid, NULL);
730 731 732 733 734 735 736 737 738 739 740 741 742

    /* close each stream */
    if (is->audio_stream >= 0)
        stream_component_close(ffp, is->audio_stream);
    if (is->video_stream >= 0)
        stream_component_close(ffp, is->video_stream);
#ifdef FFP_MERGE
    if (is->subtitle_stream >= 0)
        stream_component_close(ffp, is->subtitle_stream);
#endif

    avformat_close_input(&is->ic);

743
    av_log(NULL, AV_LOG_DEBUG, "wait for video_refresh_tid\n");
Z
Zhang Rui 已提交
744 745
    SDL_WaitThread(is->video_refresh_tid, NULL);

746 747
    packet_queue_destroy(&is->videoq);
    packet_queue_destroy(&is->audioq);
Z
Zhang Rui 已提交
748
#ifdef FFP_MERGE
749
    packet_queue_destroy(&is->subtitleq);
Z
Zhang Rui 已提交
750
#endif
751 752

    /* free all pictures */
753
    frame_queue_destory(&is->pictq);
Z
Zhang Rui 已提交
754
    frame_queue_destory(&is->sampq);
Z
Zhang Rui 已提交
755
#ifdef FFP_MERGE
756
    frame_queue_destory(&is->subpq);
Z
Zhang Rui 已提交
757
#endif
758
    SDL_DestroyCond(is->continue_read_thread);
759
    SDL_DestroyMutex(is->play_mutex);
Z
Zhang Rui 已提交
760
#if !CONFIG_AVFILTER
761
    sws_freeContext(is->img_convert_ctx);
Z
Zhang Rui 已提交
762
#endif
763 764
#ifdef FFP_MERGE
    sws_freeContext(is->sub_convert_ctx);
765
#endif
766
    av_free(is->filename);
767 768 769
    av_free(is);
}

Z
Zhang Rui 已提交
770 771 772 773
// FFP_MERGE: do_exit
// FFP_MERGE: sigterm_handler
// FFP_MERGE: video_open
// FFP_MERGE: video_display
774 775

/* display the current picture, if any */
Z
Zhang Rui 已提交
776
static void video_display2(FFPlayer *ffp)
777
{
Z
Zhang Rui 已提交
778 779 780
    VideoState *is = ffp->is;
    if (is->video_st)
        video_image_display2(ffp);
781 782
}

Z
Zhang Rui 已提交
783
static double get_clock(Clock *c)
784
{
Z
Zhang Rui 已提交
785
    if (*c->queue_serial != c->serial)
786
        return NAN;
Z
Zhang Rui 已提交
787 788
    if (c->paused) {
        return c->pts;
789
    } else {
Z
Zhang Rui 已提交
790
        double time = av_gettime_relative() / 1000000.0;
Z
Zhang Rui 已提交
791
        return c->pts_drift + time - (time - c->last_updated) * (1.0 - c->speed);
792 793 794
    }
}

Z
Zhang Rui 已提交
795
static void set_clock_at(Clock *c, double pts, int serial, double time)
796
{
Z
Zhang Rui 已提交
797 798 799 800
    c->pts = pts;
    c->last_updated = time;
    c->pts_drift = c->pts - time;
    c->serial = serial;
801 802
}

Z
Zhang Rui 已提交
803
static void set_clock(Clock *c, double pts, int serial)
804
{
Z
Zhang Rui 已提交
805
    double time = av_gettime_relative() / 1000000.0;
Z
Zhang Rui 已提交
806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828
    set_clock_at(c, pts, serial, time);
}

static void set_clock_speed(Clock *c, double speed)
{
    set_clock(c, get_clock(c), c->serial);
    c->speed = speed;
}

static void init_clock(Clock *c, int *queue_serial)
{
    c->speed = 1.0;
    c->paused = 0;
    c->queue_serial = queue_serial;
    set_clock(c, NAN, -1);
}

static void sync_clock_to_slave(Clock *c, Clock *slave)
{
    double clock = get_clock(c);
    double slave_clock = get_clock(slave);
    if (!isnan(slave_clock) && (isnan(clock) || fabs(clock - slave_clock) > AV_NOSYNC_THRESHOLD))
        set_clock(c, slave_clock, slave->serial);
829 830
}

Z
Zhang Rui 已提交
831
static int get_master_sync_type(VideoState *is) {
832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852
    if (is->av_sync_type == AV_SYNC_VIDEO_MASTER) {
        if (is->video_st)
            return AV_SYNC_VIDEO_MASTER;
        else
            return AV_SYNC_AUDIO_MASTER;
    } else if (is->av_sync_type == AV_SYNC_AUDIO_MASTER) {
        if (is->audio_st)
            return AV_SYNC_AUDIO_MASTER;
        else
            return AV_SYNC_EXTERNAL_CLOCK;
    } else {
        return AV_SYNC_EXTERNAL_CLOCK;
    }
}

/* get the current master clock value */
static double get_master_clock(VideoState *is)
{
    double val;

    switch (get_master_sync_type(is)) {
Z
Zhang Rui 已提交
853
        case AV_SYNC_VIDEO_MASTER:
Z
Zhang Rui 已提交
854
            val = get_clock(&is->vidclk);
Z
Zhang Rui 已提交
855 856
            break;
        case AV_SYNC_AUDIO_MASTER:
Z
Zhang Rui 已提交
857
            val = get_clock(&is->audclk);
Z
Zhang Rui 已提交
858 859
            break;
        default:
Z
Zhang Rui 已提交
860
            val = get_clock(&is->extclk);
Z
Zhang Rui 已提交
861
            break;
862 863 864 865
    }
    return val;
}

Z
Zhang Rui 已提交
866
static void check_external_clock_speed(VideoState *is) {
867 868
   if ((is->video_stream >= 0 && is->videoq.nb_packets <= EXTERNAL_CLOCK_MIN_FRAMES) ||
       (is->audio_stream >= 0 && is->audioq.nb_packets <= EXTERNAL_CLOCK_MIN_FRAMES)) {
Z
Zhang Rui 已提交
869
       set_clock_speed(&is->extclk, FFMAX(EXTERNAL_CLOCK_SPEED_MIN, is->extclk.speed - EXTERNAL_CLOCK_SPEED_STEP));
870 871
   } else if ((is->video_stream < 0 || is->videoq.nb_packets > EXTERNAL_CLOCK_MAX_FRAMES) &&
              (is->audio_stream < 0 || is->audioq.nb_packets > EXTERNAL_CLOCK_MAX_FRAMES)) {
Z
Zhang Rui 已提交
872
       set_clock_speed(&is->extclk, FFMIN(EXTERNAL_CLOCK_SPEED_MAX, is->extclk.speed + EXTERNAL_CLOCK_SPEED_STEP));
Z
Zhang Rui 已提交
873
   } else {
Z
Zhang Rui 已提交
874
       double speed = is->extclk.speed;
Z
Zhang Rui 已提交
875
       if (speed != 1.0)
Z
Zhang Rui 已提交
876
           set_clock_speed(&is->extclk, speed + EXTERNAL_CLOCK_SPEED_STEP * (1.0 - speed) / fabs(1.0 - speed));
Z
Zhang Rui 已提交
877
   }
878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894
}

/* seek in the stream */
static void stream_seek(VideoState *is, int64_t pos, int64_t rel, int seek_by_bytes)
{
    if (!is->seek_req) {
        is->seek_pos = pos;
        is->seek_rel = rel;
        is->seek_flags &= ~AVSEEK_FLAG_BYTE;
        if (seek_by_bytes)
            is->seek_flags |= AVSEEK_FLAG_BYTE;
        is->seek_req = 1;
        SDL_CondSignal(is->continue_read_thread);
    }
}

/* pause or resume the video */
895
static void stream_toggle_pause_l(FFPlayer *ffp, int pause_on)
896
{
897
    VideoState *is = ffp->is;
Z
Zhang Rui 已提交
898
    if (is->paused && !pause_on) {
899
        is->frame_timer += av_gettime_relative() / 1000000.0 - is->vidclk.last_updated;
Z
Zhang Rui 已提交
900

901
#ifdef FFP_MERGE
902
        if (is->read_pause_return != AVERROR(ENOSYS)) {
Z
Zhang Rui 已提交
903
            is->vidclk.paused = 0;
904
        }
905
#endif
Z
Zhang Rui 已提交
906
        set_clock(&is->vidclk, get_clock(&is->vidclk), is->vidclk.serial);
907
    } else {
908
    }
Z
Zhang Rui 已提交
909
    set_clock(&is->extclk, get_clock(&is->extclk), is->extclk.serial);
910
    is->paused = is->audclk.paused = is->vidclk.paused = is->extclk.paused = pause_on;
911 912

    SDL_AoutPauseAudio(ffp->aout, pause_on);
913 914
}

915 916 917 918 919 920 921 922 923 924
static void stream_update_pause_l(FFPlayer *ffp)
{
    VideoState *is = ffp->is;
    if (!is->step && (is->pause_req || is->buffering_on)) {
        stream_toggle_pause_l(ffp, 1);
    } else {
        stream_toggle_pause_l(ffp, 0);
    }
}

925
static void toggle_pause_l(FFPlayer *ffp, int pause_on)
926 927
{
    VideoState *is = ffp->is;
928
    is->pause_req = pause_on;
Z
Zhang Rui 已提交
929
    ffp->auto_resume = !pause_on;
930
    stream_update_pause_l(ffp);
931 932
    is->step = 0;
}
933

934 935 936 937 938 939 940
static void toggle_pause(FFPlayer *ffp, int pause_on)
{
    SDL_LockMutex(ffp->is->play_mutex);
    toggle_pause_l(ffp, pause_on);
    SDL_UnlockMutex(ffp->is->play_mutex);
}

941 942 943
// FFP_MERGE: toggle_mute
// FFP_MERGE: update_volume

944
static void step_to_next_frame_l(FFPlayer *ffp)
945
{
946
    VideoState *is = ffp->is;
947 948
    /* if the stream is paused unpause it, then step */
    if (is->paused)
949
        stream_toggle_pause_l(ffp, 0);
950 951
    is->step = 1;
}
952

Z
Zhang Rui 已提交
953
static double compute_target_delay(FFPlayer *ffp, double delay, VideoState *is)
954
{
955
    double sync_threshold, diff = 0;
956 957 958 959

    /* update delay to follow master synchronisation source */
    if (get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER) {
        /* if video is slave, we try to correct big delays by
Z
Zhang Rui 已提交
960
           duplicating or deleting a frame */
Z
Zhang Rui 已提交
961
        diff = get_clock(&is->vidclk) - get_master_clock(is);
962 963

        /* skip or repeat frame. We take into account the
Z
Zhang Rui 已提交
964 965
           delay to compute the threshold. I still don't know
           if it is the best guess */
Z
Zhang Rui 已提交
966
        sync_threshold = FFMAX(AV_SYNC_THRESHOLD_MIN, FFMIN(AV_SYNC_THRESHOLD_MAX, delay));
967 968
        /* -- by bbcallen: replace is->max_frame_duration with AV_NOSYNC_THRESHOLD */
        if (!isnan(diff) && fabs(diff) < AV_NOSYNC_THRESHOLD) {
969
            if (diff <= -sync_threshold)
Z
Zhang Rui 已提交
970 971 972
                delay = FFMAX(0, delay + diff);
            else if (diff >= sync_threshold && delay > AV_SYNC_FRAMEDUP_THRESHOLD)
                delay = delay + diff;
973 974 975 976 977
            else if (diff >= sync_threshold)
                delay = 2 * delay;
        }
    }

Z
Zhang Rui 已提交
978 979 980 981
    if (ffp) {
        ffp->stat.avdelay = delay;
        ffp->stat.avdiff  = diff;
    }
Z
Zhang Rui 已提交
982
#ifdef FFP_SHOW_AUDIO_DELAY
983
    av_log(NULL, AV_LOG_TRACE, "video: delay=%0.3f A-V=%f\n",
Z
Zhang Rui 已提交
984
            delay, -diff);
Z
Zhang Rui 已提交
985
#endif
986 987 988 989

    return delay;
}

990
static double vp_duration(VideoState *is, Frame *vp, Frame *nextvp) {
Z
Zhang Rui 已提交
991 992 993 994 995 996 997 998 999 1000 1001
    if (vp->serial == nextvp->serial) {
        double duration = nextvp->pts - vp->pts;
        if (isnan(duration) || duration <= 0 || duration > is->max_frame_duration)
            return vp->duration;
        else
            return duration;
    } else {
        return 0.0;
    }
}

Z
Zhang Rui 已提交
1002
static void update_video_pts(VideoState *is, double pts, int64_t pos, int serial) {
1003
    /* update current video pts */
Z
Zhang Rui 已提交
1004 1005
    set_clock(&is->vidclk, pts, serial);
    sync_clock_to_slave(&is->extclk, &is->vidclk);
1006 1007 1008 1009 1010 1011
}

/* called to display each frame */
static void video_refresh(FFPlayer *opaque, double *remaining_time)
{
    FFPlayer *ffp = opaque;
1012
    VideoState *is = ffp->is;
1013 1014
    double time;

Z
Zhang Rui 已提交
1015
#ifdef FFP_MERGE
1016
    Frame *sp, *sp2;
Z
Zhang Rui 已提交
1017
#endif
1018 1019 1020 1021 1022

    if (!is->paused && get_master_sync_type(is) == AV_SYNC_EXTERNAL_CLOCK && is->realtime)
        check_external_clock_speed(is);

    if (!ffp->display_disable && is->show_mode != SHOW_MODE_VIDEO && is->audio_st) {
Z
Zhang Rui 已提交
1023
        time = av_gettime_relative() / 1000000.0;
1024
        if (is->force_refresh || is->last_vis_time + ffp->rdftspeed < time) {
Z
Zhang Rui 已提交
1025
            video_display2(ffp);
1026 1027 1028 1029 1030 1031 1032 1033
            is->last_vis_time = time;
        }
        *remaining_time = FFMIN(*remaining_time, is->last_vis_time + ffp->rdftspeed - time);
    }

    if (is->video_st) {
        int redisplay = 0;
        if (is->force_refresh)
1034
            redisplay = frame_queue_prev(&is->pictq);
Z
Zhang Rui 已提交
1035
retry:
1036
        if (frame_queue_nb_remaining(&is->pictq) == 0) {
1037 1038 1039
            // nothing to do, no picture to display in the queue
        } else {
            double last_duration, duration, delay;
1040
            Frame *vp, *lastvp;
Z
Zhang Rui 已提交
1041

1042
            /* dequeue the picture */
1043 1044
            lastvp = frame_queue_peek_last(&is->pictq);
            vp = frame_queue_peek(&is->pictq);
1045 1046

            if (vp->serial != is->videoq.serial) {
1047
                frame_queue_next(&is->pictq);
1048 1049 1050 1051
                redisplay = 0;
                goto retry;
            }

Z
Zhang Rui 已提交
1052
            if (lastvp->serial != vp->serial && !redisplay)
Z
Zhang Rui 已提交
1053
                is->frame_timer = av_gettime_relative() / 1000000.0;
Z
Zhang Rui 已提交
1054

1055 1056 1057 1058
            if (is->paused)
                goto display;

            /* compute nominal last_duration */
Z
Zhang Rui 已提交
1059
            last_duration = vp_duration(is, lastvp, vp);
Z
Zhang Rui 已提交
1060 1061 1062
            if (redisplay)
                delay = 0.0;
            else
Z
Zhang Rui 已提交
1063
                delay = compute_target_delay(ffp, last_duration, is);
1064

Z
Zhang Rui 已提交
1065
            time= av_gettime_relative()/1000000.0;
Z
Zhang Rui 已提交
1066 1067
            if (isnan(is->frame_timer) || time < is->frame_timer)
                is->frame_timer = time;
Z
Zhang Rui 已提交
1068
            if (time < is->frame_timer + delay && !redisplay) {
1069 1070 1071 1072
                *remaining_time = FFMIN(is->frame_timer + delay - time, *remaining_time);
                return;
            }

Z
Zhang Rui 已提交
1073 1074 1075
            is->frame_timer += delay;
            if (delay > 0 && time - is->frame_timer > AV_SYNC_THRESHOLD_MAX)
                is->frame_timer = time;
1076

1077
            SDL_LockMutex(is->pictq.mutex);
Z
Zhang Rui 已提交
1078 1079
            if (!redisplay && !isnan(vp->pts))
                update_video_pts(is, vp->pts, vp->pos, vp->serial);
1080
            SDL_UnlockMutex(is->pictq.mutex);
1081

1082 1083
            if (frame_queue_nb_remaining(&is->pictq) > 1) {
                Frame *nextvp = frame_queue_peek_next(&is->pictq);
Z
Zhang Rui 已提交
1084
                duration = vp_duration(is, vp, nextvp);
Z
Zhang Rui 已提交
1085
                if(!is->step && (redisplay || ffp->framedrop > 0 || (ffp->framedrop && get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER)) && time > is->frame_timer + duration) {
1086 1087
                    if (!redisplay)
                        is->frame_drops_late++;
1088
                    frame_queue_next(&is->pictq);
1089 1090 1091 1092 1093
                    redisplay = 0;
                    goto retry;
                }
            }

Z
Zhang Rui 已提交
1094
            // FFP_MERGE: if (is->subtitle_st) { {...}
1095

Z
Zhang Rui 已提交
1096
display:
1097 1098
            /* display picture */
            if (!ffp->display_disable && is->show_mode == SHOW_MODE_VIDEO)
Z
Zhang Rui 已提交
1099
                video_display2(ffp);
1100

1101
            frame_queue_next(&is->pictq);
1102

1103
            SDL_LockMutex(ffp->is->play_mutex);
1104 1105 1106 1107 1108
            if (is->step) {
                is->step = 0;
                if (!is->paused)
                    stream_update_pause_l(ffp);
            }
1109
            SDL_UnlockMutex(ffp->is->play_mutex);
1110 1111 1112
        }
    }
    is->force_refresh = 0;
Z
Zhang Rui 已提交
1113 1114 1115
    if (ffp->show_status) {
        static int64_t last_time;
        int64_t cur_time;
Z
Zhang Rui 已提交
1116
        int aqsize, vqsize, sqsize __unused;
Z
Zhang Rui 已提交
1117 1118
        double av_diff;

Z
Zhang Rui 已提交
1119
        cur_time = av_gettime_relative();
Z
Zhang Rui 已提交
1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155
        if (!last_time || (cur_time - last_time) >= 30000) {
            aqsize = 0;
            vqsize = 0;
            sqsize = 0;
            if (is->audio_st)
                aqsize = is->audioq.size;
            if (is->video_st)
                vqsize = is->videoq.size;
#ifdef FFP_MERGE
            if (is->subtitle_st)
                sqsize = is->subtitleq.size;
#else
            sqsize = 0;
#endif
            av_diff = 0;
            if (is->audio_st && is->video_st)
                av_diff = get_clock(&is->audclk) - get_clock(&is->vidclk);
            else if (is->video_st)
                av_diff = get_master_clock(is) - get_clock(&is->vidclk);
            else if (is->audio_st)
                av_diff = get_master_clock(is) - get_clock(&is->audclk);
            av_log(NULL, AV_LOG_INFO,
                   "%7.2f %s:%7.3f fd=%4d aq=%5dKB vq=%5dKB sq=%5dB f=%"PRId64"/%"PRId64"   \r",
                   get_master_clock(is),
                   (is->audio_st && is->video_st) ? "A-V" : (is->video_st ? "M-V" : (is->audio_st ? "M-A" : "   ")),
                   av_diff,
                   is->frame_drops_early + is->frame_drops_late,
                   aqsize / 1024,
                   vqsize / 1024,
                   sqsize,
                   is->video_st ? is->video_st->codec->pts_correction_num_faulty_dts : 0,
                   is->video_st ? is->video_st->codec->pts_correction_num_faulty_pts : 0);
            fflush(stdout);
            last_time = cur_time;
        }
    }
1156
}
1157

1158
/* allocate a picture (needs to do that in main thread to avoid
Z
Zhang Rui 已提交
1159
   potential locking problems */
1160
static void alloc_picture(FFPlayer *ffp, int frame_format)
1161
{
1162
    VideoState *is = ffp->is;
1163
    Frame *vp;
B
bbcallen 已提交
1164
#ifdef FFP_MERGE
Z
Zhang Rui 已提交
1165
    int64_t bufferdiff;
B
bbcallen 已提交
1166
#endif
1167

1168
    vp = &is->pictq.queue[is->pictq.windex];
1169

1170
    free_picture(vp);
1171

Z
Zhang Rui 已提交
1172
#ifdef FFP_MERGE
1173
    video_open(ffp, 0, vp);
Z
Zhang Rui 已提交
1174
#endif
1175

1176
    SDL_VoutSetOverlayFormat(ffp->vout, ffp->overlay_format);
1177
    vp->bmp = SDL_Vout_CreateOverlay(vp->width, vp->height,
1178
                                   frame_format,
Z
Zhang Rui 已提交
1179
                                   ffp->vout);
1180
#ifdef FFP_MERGE
Z
Zhang Rui 已提交
1181 1182
    bufferdiff = vp->bmp ? FFMAX(vp->bmp->pixels[0], vp->bmp->pixels[1]) - FFMIN(vp->bmp->pixels[0], vp->bmp->pixels[1]) : 0;
    if (!vp->bmp || vp->bmp->pitches[0] < vp->width || bufferdiff < (int64_t)vp->height * vp->bmp->pitches[0]) {
1183 1184
#else
    /* RV16, RV32 contains only one plane */
1185
    if (!vp->bmp || (!vp->bmp->is_private && vp->bmp->pitches[0] < vp->width)) {
1186
#endif
1187 1188
        /* SDL allocates a buffer smaller than requested if the video
         * overlay hardware is unable to support the requested size. */
Z
Zhang Rui 已提交
1189 1190
        av_log(NULL, AV_LOG_FATAL,
               "Error: the video system does not support an image\n"
Z
Zhang Rui 已提交
1191 1192
                        "size of %dx%d pixels. Try using -lowres or -vf \"scale=w:h\"\n"
                        "to reduce the image size.\n", vp->width, vp->height );
1193
        free_picture(vp);
1194 1195
    }

1196
    SDL_LockMutex(is->pictq.mutex);
1197
    vp->allocated = 1;
1198 1199
    SDL_CondSignal(is->pictq.cond);
    SDL_UnlockMutex(is->pictq.mutex);
1200 1201
}

Z
Zhang Rui 已提交
1202
#ifdef FFP_MERGE
Z
Zhang Rui 已提交
1203
static void duplicate_right_border_pixels(SDL_Overlay *bmp) {
1204 1205 1206
    int i, width, height;
    Uint8 *p, *maxp;
    for (i = 0; i < 3; i++) {
Z
Zhang Rui 已提交
1207
        width  = bmp->w;
1208 1209
        height = bmp->h;
        if (i > 0) {
Z
Zhang Rui 已提交
1210
            width  >>= 1;
1211 1212 1213 1214 1215
            height >>= 1;
        }
        if (bmp->pitches[i] > width) {
            maxp = bmp->pixels[i] + bmp->pitches[i] * height - 1;
            for (p = bmp->pixels[i] + width - 1; p < maxp; p += bmp->pitches[i])
Z
Zhang Rui 已提交
1216
                *(p+1) = *p;
1217 1218 1219
        }
    }
}
Z
Zhang Rui 已提交
1220
#endif
1221

Z
Zhang Rui 已提交
1222
static int queue_picture(FFPlayer *ffp, AVFrame *src_frame, double pts, double duration, int64_t pos, int serial)
1223
{
1224
    VideoState *is = ffp->is;
1225
    Frame *vp;
1226 1227 1228

#if defined(DEBUG_SYNC) && 0
    printf("frame_type=%c pts=%0.3f\n",
Z
Zhang Rui 已提交
1229
           av_get_picture_type_char(src_frame->pict_type), pts);
1230 1231
#endif

1232
    if (!(vp = frame_queue_peek_writable(&is->pictq)))
1233 1234 1235 1236
        return -1;

    /* alloc or resize hardware picture buffer */
    if (!vp->bmp || vp->reallocate || !vp->allocated ||
Z
Zhang Rui 已提交
1237
        vp->width  != src_frame->width ||
Z
Zhang Rui 已提交
1238
        vp->height != src_frame->height) {
Z
Zhang Rui 已提交
1239 1240

        if (vp->width != src_frame->width || vp->height != src_frame->height)
1241
            ffp_notify_msg3(ffp, FFP_MSG_VIDEO_SIZE_CHANGED, src_frame->width, src_frame->height);
Z
Zhang Rui 已提交
1242

Z
Zhang Rui 已提交
1243
        vp->allocated  = 0;
1244 1245 1246 1247 1248
        vp->reallocate = 0;
        vp->width = src_frame->width;
        vp->height = src_frame->height;

        /* the allocation must be done in the main thread to avoid
Z
Zhang Rui 已提交
1249
           locking problems. */
1250
        alloc_picture(ffp, src_frame->format);
1251 1252 1253 1254 1255 1256 1257 1258

        if (is->videoq.abort_request)
            return -1;
    }

    /* if the frame is not skipped, then display it */
    if (vp->bmp) {
        /* get a pointer on the bitmap */
Z
Zhang Rui 已提交
1259
        SDL_VoutLockYUVOverlay(vp->bmp);
1260

Z
Zhang Rui 已提交
1261 1262 1263 1264 1265 1266 1267 1268 1269
#ifdef FFP_MERGE
#if CONFIG_AVFILTER
        // FIXME use direct rendering
        av_picture_copy(&pict, (AVPicture *)src_frame,
                        src_frame->format, vp->width, vp->height);
#else
        // sws_getCachedContext(...);
#endif
#endif
Z
Zhang Rui 已提交
1270
        // FIXME: set swscale options
1271
        if (SDL_VoutFillFrameYUVOverlay(vp->bmp, src_frame) < 0) {
Z
Zhang Rui 已提交
1272
            av_log(NULL, AV_LOG_FATAL, "Cannot initialize the conversion context\n");
1273 1274 1275
            exit(1);
        }
        /* update the bitmap content */
1276
        SDL_VoutUnlockYUVOverlay(vp->bmp);
1277 1278

        vp->pts = pts;
Z
Zhang Rui 已提交
1279
        vp->duration = duration;
1280 1281
        vp->pos = pos;
        vp->serial = serial;
1282
        vp->sar = src_frame->sample_aspect_ratio;
1283

Z
Zhang Rui 已提交
1284 1285 1286
        vp->bmp->sar_num = vp->sar.num;
        vp->bmp->sar_den = vp->sar.den;

1287
        /* now we can update the picture count */
1288
        frame_queue_push(&is->pictq);
Z
Zhang Rui 已提交
1289
        if (!is->viddec.first_frame_decoded) {
1290
            ALOGD("Video: first frame decoded\n");
Z
Zhang Rui 已提交
1291 1292 1293
            is->viddec.first_frame_decoded_time = SDL_GetTickHR();
            is->viddec.first_frame_decoded = 1;
        }
1294 1295 1296 1297
    }
    return 0;
}

1298
static int get_video_frame(FFPlayer *ffp, AVFrame *frame)
1299
{
1300
    VideoState *is = ffp->is;
1301 1302
    int got_picture;

1303
    ffp_video_statistic_l(ffp);
1304
    if ((got_picture = decoder_decode_frame(ffp, &is->viddec, frame, NULL)) < 0)
1305
        return -1;
1306 1307

    if (got_picture) {
Z
Zhang Rui 已提交
1308
        double dpts = NAN;
1309

Z
Zhang Rui 已提交
1310 1311 1312 1313
        if (frame->pts != AV_NOPTS_VALUE)
            dpts = av_q2d(is->video_st->time_base) * frame->pts;

        frame->sample_aspect_ratio = av_guess_sample_aspect_ratio(is->ic, is->video_st, frame);
1314

1315 1316 1317 1318 1319
#ifdef FFP_MERGE
        is->viddec_width  = frame->width;
        is->viddec_height = frame->height;
#endif

B
bbcallen 已提交
1320
        if (ffp->framedrop>0 || (ffp->framedrop && get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER)) {
Z
Zhang Rui 已提交
1321 1322 1323 1324
            if (frame->pts != AV_NOPTS_VALUE) {
                double diff = dpts - get_master_clock(is);
                if (!isnan(diff) && fabs(diff) < AV_NOSYNC_THRESHOLD &&
                    diff - is->frame_last_filter_delay < 0 &&
1325
                    is->viddec.pkt_serial == is->vidclk.serial &&
Z
Zhang Rui 已提交
1326
                    is->videoq.nb_packets) {
B
bbcallen 已提交
1327
                    is->frame_drops_early++;
Z
Zhang Rui 已提交
1328 1329 1330 1331 1332 1333 1334
                    is->continuous_frame_drops_early++;
                    if (is->continuous_frame_drops_early > ffp->framedrop) {
                        is->continuous_frame_drops_early = 0;
                    } else {
                        av_frame_unref(frame);
                        got_picture = 0;
                    }
1335 1336 1337 1338
                }
            }
        }
    }
Z
Zhang Rui 已提交
1339

1340
    return got_picture;
1341 1342
}

1343 1344
#if CONFIG_AVFILTER
static int configure_filtergraph(AVFilterGraph *graph, const char *filtergraph,
Z
Zhang Rui 已提交
1345
                                 AVFilterContext *source_ctx, AVFilterContext *sink_ctx)
1346
{
Z
Zhang Rui 已提交
1347 1348
    int ret, i;
    int nb_filters = graph->nb_filters;
1349 1350 1351 1352
    AVFilterInOut *outputs = NULL, *inputs = NULL;

    if (filtergraph) {
        outputs = avfilter_inout_alloc();
Z
Zhang Rui 已提交
1353
        inputs  = avfilter_inout_alloc();
1354 1355 1356 1357 1358
        if (!outputs || !inputs) {
            ret = AVERROR(ENOMEM);
            goto fail;
        }

Z
Zhang Rui 已提交
1359
        outputs->name       = av_strdup("in");
1360
        outputs->filter_ctx = source_ctx;
Z
Zhang Rui 已提交
1361 1362
        outputs->pad_idx    = 0;
        outputs->next       = NULL;
1363

Z
Zhang Rui 已提交
1364 1365 1366 1367
        inputs->name        = av_strdup("out");
        inputs->filter_ctx  = sink_ctx;
        inputs->pad_idx     = 0;
        inputs->next        = NULL;
1368

Z
Zhang Rui 已提交
1369
        if ((ret = avfilter_graph_parse_ptr(graph, filtergraph, &inputs, &outputs, NULL)) < 0)
Z
Zhang Rui 已提交
1370
            goto fail;
1371 1372
    } else {
        if ((ret = avfilter_link(source_ctx, 0, sink_ctx, 0)) < 0)
Z
Zhang Rui 已提交
1373
            goto fail;
1374 1375
    }

Z
Zhang Rui 已提交
1376 1377 1378 1379
    /* Reorder the filters to ensure that inputs of the custom filters are merged first */
    for (i = 0; i < graph->nb_filters - nb_filters; i++)
        FFSWAP(AVFilterContext*, graph->filters[i], graph->filters[i + nb_filters]);

1380
    ret = avfilter_graph_config(graph, NULL);
Z
Zhang Rui 已提交
1381
fail:
1382 1383 1384 1385 1386
    avfilter_inout_free(&outputs);
    avfilter_inout_free(&inputs);
    return ret;
}

Z
Zhang Rui 已提交
1387
static int configure_video_filters(FFPlayer *ffp, AVFilterGraph *graph, VideoState *is, const char *vfilters, AVFrame *frame)
1388
{
Z
Zhang Rui 已提交
1389
    static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE };
1390
    char sws_flags_str[512] = "";
1391 1392
    char buffersrc_args[256];
    int ret;
Z
Zhang Rui 已提交
1393
    AVFilterContext *filt_src = NULL, *filt_out = NULL, *last_filter = NULL;
1394
    AVCodecContext *codec = is->video_st->codec;
Z
Zhang Rui 已提交
1395
    AVRational fr = av_guess_frame_rate(is->ic, is->video_st, NULL);
1396 1397
    AVDictionaryEntry *e = NULL;

Z
Zhang Rui 已提交
1398
    while ((e = av_dict_get(ffp->sws_dict, "", e, AV_DICT_IGNORE_SUFFIX))) {
1399 1400 1401 1402 1403 1404 1405
        if (!strcmp(e->key, "sws_flags")) {
            av_strlcatf(sws_flags_str, sizeof(sws_flags_str), "%s=%s:", "flags", e->value);
        } else
            av_strlcatf(sws_flags_str, sizeof(sws_flags_str), "%s=%s:", e->key, e->value);
    }
    if (strlen(sws_flags_str))
        sws_flags_str[strlen(sws_flags_str)-1] = '\0';
1406 1407 1408 1409

    graph->scale_sws_opts = av_strdup(sws_flags_str);

    snprintf(buffersrc_args, sizeof(buffersrc_args),
Z
Zhang Rui 已提交
1410 1411 1412 1413
             "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
             frame->width, frame->height, frame->format,
             is->video_st->time_base.num, is->video_st->time_base.den,
             codec->sample_aspect_ratio.num, FFMAX(codec->sample_aspect_ratio.den, 1));
Z
Zhang Rui 已提交
1414 1415
    if (fr.num && fr.den)
        av_strlcatf(buffersrc_args, sizeof(buffersrc_args), ":frame_rate=%d/%d", fr.num, fr.den);
1416 1417

    if ((ret = avfilter_graph_create_filter(&filt_src,
Z
Zhang Rui 已提交
1418 1419 1420 1421
                                            avfilter_get_by_name("buffer"),
                                            "ffplay_buffer", buffersrc_args, NULL,
                                            graph)) < 0)
        goto fail;
1422 1423

    ret = avfilter_graph_create_filter(&filt_out,
Z
Zhang Rui 已提交
1424 1425
                                       avfilter_get_by_name("buffersink"),
                                       "ffplay_buffersink", NULL, NULL, graph);
1426
    if (ret < 0)
Z
Zhang Rui 已提交
1427
        goto fail;
1428

Z
Zhang Rui 已提交
1429 1430 1431
    if ((ret = av_opt_set_int_list(filt_out, "pix_fmts", pix_fmts,  AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN)) < 0)
        goto fail;

Z
Zhang Rui 已提交
1432 1433 1434 1435
    last_filter = filt_out;

/* Note: this macro adds a filter before the lastly added filter, so the
 * processing order of the filters is in reverse */
1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449
#define INSERT_FILT(name, arg) do {                                          \
    AVFilterContext *filt_ctx;                                               \
                                                                             \
    ret = avfilter_graph_create_filter(&filt_ctx,                            \
                                       avfilter_get_by_name(name),           \
                                       "ffplay_" name, arg, NULL, graph);    \
    if (ret < 0)                                                             \
        goto fail;                                                           \
                                                                             \
    ret = avfilter_link(filt_ctx, 0, last_filter, 0);                        \
    if (ret < 0)                                                             \
        goto fail;                                                           \
                                                                             \
    last_filter = filt_ctx;                                                  \
Z
Zhang Rui 已提交
1450 1451
} while (0)

1452 1453
    /* SDL YUV code is not handling odd width/height for some driver
     * combinations, therefore we crop the picture to an even width/height. */
Z
Zhang Rui 已提交
1454 1455
    INSERT_FILT("crop", "floor(in_w/2)*2:floor(in_h/2)*2");

Z
Zhang Rui 已提交
1456
    if (ffp->autorotate) {
1457
        double theta  = get_rotation(is->video_st);
1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469

        if (fabs(theta - 90) < 1.0) {
            INSERT_FILT("transpose", "clock");
        } else if (fabs(theta - 180) < 1.0) {
            INSERT_FILT("hflip", NULL);
            INSERT_FILT("vflip", NULL);
        } else if (fabs(theta - 270) < 1.0) {
            INSERT_FILT("transpose", "cclock");
        } else if (fabs(theta) > 1.0) {
            char rotate_buf[64];
            snprintf(rotate_buf, sizeof(rotate_buf), "%f*PI/180", theta);
            INSERT_FILT("rotate", rotate_buf);
Z
Zhang Rui 已提交
1470 1471
        }
    }
1472

Z
Zhang Rui 已提交
1473
#ifdef FFP_AVFILTER_PLAYBACK_RATE
Z
Zhang Rui 已提交
1474 1475 1476 1477 1478 1479 1480 1481 1482
    if (fabsf(ffp->pf_playback_rate) > 0.00001 &&
        fabsf(ffp->pf_playback_rate - 1.0f) > 0.00001) {
        char setpts_buf[256];
        float rate = 1.0f / ffp->pf_playback_rate;
        rate = av_clipf_c(rate, 0.5f, 2.0f);
        av_log(ffp, AV_LOG_INFO, "vf_rate=%f(1/%f)\n", ffp->pf_playback_rate, rate);
        snprintf(setpts_buf, sizeof(setpts_buf), "%f*PTS", rate);
        INSERT_FILT("setpts", setpts_buf);
    }
Z
Zhang Rui 已提交
1483
#endif
Z
Zhang Rui 已提交
1484

Z
Zhang Rui 已提交
1485
    if ((ret = configure_filtergraph(graph, vfilters, filt_src, last_filter)) < 0)
Z
Zhang Rui 已提交
1486
        goto fail;
1487

Z
Zhang Rui 已提交
1488
    is->in_video_filter  = filt_src;
1489 1490
    is->out_video_filter = filt_out;

Z
Zhang Rui 已提交
1491
fail:
1492 1493 1494
    return ret;
}

Z
Zhang Rui 已提交
1495
static int configure_audio_filters(FFPlayer *ffp, const char *afilters, int force_output_format)
Z
Zhang Rui 已提交
1496
{
Z
Zhang Rui 已提交
1497
    VideoState *is = ffp->is;
Z
Zhang Rui 已提交
1498 1499 1500 1501 1502
    static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_NONE };
    int sample_rates[2] = { 0, -1 };
    int64_t channel_layouts[2] = { 0, -1 };
    int channels[2] = { 0, -1 };
    AVFilterContext *filt_asrc = NULL, *filt_asink = NULL;
1503 1504
    char aresample_swr_opts[512] = "";
    AVDictionaryEntry *e = NULL;
Z
Zhang Rui 已提交
1505 1506
    char asrc_args[256];
    int ret;
Z
Zhang Rui 已提交
1507
    char afilters_args[4096];
Z
Zhang Rui 已提交
1508 1509 1510 1511 1512

    avfilter_graph_free(&is->agraph);
    if (!(is->agraph = avfilter_graph_alloc()))
        return AVERROR(ENOMEM);

Z
Zhang Rui 已提交
1513
    while ((e = av_dict_get(ffp->swr_opts, "", e, AV_DICT_IGNORE_SUFFIX)))
1514 1515 1516 1517 1518
        av_strlcatf(aresample_swr_opts, sizeof(aresample_swr_opts), "%s=%s:", e->key, e->value);
    if (strlen(aresample_swr_opts))
        aresample_swr_opts[strlen(aresample_swr_opts)-1] = '\0';
    av_opt_set(is->agraph, "aresample_swr_opts", aresample_swr_opts, 0);

Z
Zhang Rui 已提交
1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559
    ret = snprintf(asrc_args, sizeof(asrc_args),
                   "sample_rate=%d:sample_fmt=%s:channels=%d:time_base=%d/%d",
                   is->audio_filter_src.freq, av_get_sample_fmt_name(is->audio_filter_src.fmt),
                   is->audio_filter_src.channels,
                   1, is->audio_filter_src.freq);
    if (is->audio_filter_src.channel_layout)
        snprintf(asrc_args + ret, sizeof(asrc_args) - ret,
                 ":channel_layout=0x%"PRIx64,  is->audio_filter_src.channel_layout);

    ret = avfilter_graph_create_filter(&filt_asrc,
                                       avfilter_get_by_name("abuffer"), "ffplay_abuffer",
                                       asrc_args, NULL, is->agraph);
    if (ret < 0)
        goto end;


    ret = avfilter_graph_create_filter(&filt_asink,
                                       avfilter_get_by_name("abuffersink"), "ffplay_abuffersink",
                                       NULL, NULL, is->agraph);
    if (ret < 0)
        goto end;

    if ((ret = av_opt_set_int_list(filt_asink, "sample_fmts", sample_fmts,  AV_SAMPLE_FMT_NONE, AV_OPT_SEARCH_CHILDREN)) < 0)
        goto end;
    if ((ret = av_opt_set_int(filt_asink, "all_channel_counts", 1, AV_OPT_SEARCH_CHILDREN)) < 0)
        goto end;

    if (force_output_format) {
        channel_layouts[0] = is->audio_tgt.channel_layout;
        channels       [0] = is->audio_tgt.channels;
        sample_rates   [0] = is->audio_tgt.freq;
        if ((ret = av_opt_set_int(filt_asink, "all_channel_counts", 0, AV_OPT_SEARCH_CHILDREN)) < 0)
            goto end;
        if ((ret = av_opt_set_int_list(filt_asink, "channel_layouts", channel_layouts,  -1, AV_OPT_SEARCH_CHILDREN)) < 0)
            goto end;
        if ((ret = av_opt_set_int_list(filt_asink, "channel_counts" , channels       ,  -1, AV_OPT_SEARCH_CHILDREN)) < 0)
            goto end;
        if ((ret = av_opt_set_int_list(filt_asink, "sample_rates"   , sample_rates   ,  -1, AV_OPT_SEARCH_CHILDREN)) < 0)
            goto end;
    }

Z
Zhang Rui 已提交
1560 1561 1562 1563
    afilters_args[0] = 0;
    if (afilters)
        snprintf(afilters_args, sizeof(afilters_args), "%s", afilters);

Z
Zhang Rui 已提交
1564
#ifdef FFP_AVFILTER_PLAYBACK_RATE
Z
Zhang Rui 已提交
1565 1566 1567 1568 1569 1570 1571 1572
    if (fabsf(ffp->pf_playback_rate) > 0.00001 &&
        fabsf(ffp->pf_playback_rate - 1.0f) > 0.00001) {
        if (afilters_args[0])
            av_strlcatf(afilters_args, sizeof(afilters_args), ",");

        av_log(ffp, AV_LOG_INFO, "af_rate=%f\n", ffp->pf_playback_rate);
        av_strlcatf(afilters_args, sizeof(afilters_args), "atempo=%f", ffp->pf_playback_rate);
    }
Z
Zhang Rui 已提交
1573
#endif
Z
Zhang Rui 已提交
1574

Z
Zhang Rui 已提交
1575
    if ((ret = configure_filtergraph(is->agraph, afilters_args[0] ? afilters_args : NULL, filt_asrc, filt_asink)) < 0)
Z
Zhang Rui 已提交
1576 1577 1578 1579 1580 1581 1582 1583 1584 1585
        goto end;

    is->in_audio_filter  = filt_asrc;
    is->out_audio_filter = filt_asink;

end:
    if (ret < 0)
        avfilter_graph_free(&is->agraph);
    return ret;
}
1586 1587
#endif  /* CONFIG_AVFILTER */

1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602
static int audio_thread(void *arg)
{
    FFPlayer *ffp = arg;
    VideoState *is = ffp->is;
    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;

1603
    if (!frame) {
1604
        return AVERROR(ENOMEM);
1605
    }
1606 1607

    do {
1608
        ffp_audio_statistic_l(ffp);
1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621
        if ((got_frame = decoder_decode_frame(ffp, &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 ||
Z
Zhang Rui 已提交
1622
                    is->audio_filter_src.freq           != frame->sample_rate ||
Z
Zhang Rui 已提交
1623 1624
                    is->auddec.pkt_serial               != last_serial        ||
                    ffp->af_changed;
1625 1626

                if (reconfigure) {
Z
Zhang Rui 已提交
1627 1628
                    SDL_LockMutex(ffp->af_mutex);
                    ffp->af_changed = 0;
1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642
                    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;

Z
Zhang Rui 已提交
1643 1644
                    if ((ret = configure_audio_filters(ffp, ffp->afilters, 1)) < 0) {
                        SDL_UnlockMutex(ffp->af_mutex);
1645
                        goto the_end;
Z
Zhang Rui 已提交
1646 1647
                    }
                    SDL_UnlockMutex(ffp->af_mutex);
1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683
                }

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

1684
static int decoder_start(Decoder *d, int (*fn)(void *), void *arg, const char *name)
1685 1686 1687
{
    packet_queue_start(d->queue);
    d->decoder_tid = SDL_CreateThreadEx(&d->_decoder_tid, fn, arg, name);
1688
    if (!d->decoder_tid) {
1689
        av_log(NULL, AV_LOG_ERROR, "SDL_CreateThread(): %s\n", SDL_GetError());
1690 1691 1692
        return AVERROR(ENOMEM);
    }
    return 0;
1693 1694
}

Z
Zhang Rui 已提交
1695
static int ffplay_video_thread(void *arg)
1696 1697
{
    FFPlayer *ffp = arg;
1698
    VideoState *is = ffp->is;
Z
Zhang Rui 已提交
1699
    AVFrame *frame = av_frame_alloc();
1700
    double pts;
Z
Zhang Rui 已提交
1701
    double duration;
1702
    int ret;
Z
Zhang Rui 已提交
1703 1704
    AVRational tb = is->video_st->time_base;
    AVRational frame_rate = av_guess_frame_rate(is->ic, is->video_st, NULL);
1705 1706 1707 1708 1709 1710 1711 1712

#if CONFIG_AVFILTER
    AVFilterGraph *graph = avfilter_graph_alloc();
    AVFilterContext *filt_out = NULL, *filt_in = NULL;
    int last_w = 0;
    int last_h = 0;
    enum AVPixelFormat last_format = -2;
    int last_serial = -1;
Z
Zhang Rui 已提交
1713
    int last_vfilter_idx = 0;
1714 1715
    if (!graph) {
        av_frame_free(&frame);
1716
        return AVERROR(ENOMEM);
1717
    }
Z
Zhang Rui 已提交
1718 1719
#else
    ffp_notify_msg2(ffp, FFP_MSG_VIDEO_ROTATION_CHANGED, ffp_get_video_rotate_degrees(ffp));
1720 1721
#endif

Z
Zhang Rui 已提交
1722 1723 1724 1725
    if (!frame) {
#if CONFIG_AVFILTER
        avfilter_graph_free(&graph);
#endif
1726
        return AVERROR(ENOMEM);
Z
Zhang Rui 已提交
1727
    }
1728

1729
    for (;;) {
1730
        ret = get_video_frame(ffp, frame);
1731 1732 1733 1734 1735 1736
        if (ret < 0)
            goto the_end;
        if (!ret)
            continue;

#if CONFIG_AVFILTER
Z
Zhang Rui 已提交
1737
        if (   last_w != frame->width
Z
Zhang Rui 已提交
1738 1739
            || last_h != frame->height
            || last_format != frame->format
1740
            || last_serial != is->viddec.pkt_serial
Z
Zhang Rui 已提交
1741 1742 1743 1744
            || last_vfilter_idx != is->vfilter_idx
            || ffp->vf_changed) {
            SDL_LockMutex(ffp->vf_mutex);
            ffp->vf_changed = 0;
1745
            av_log(NULL, AV_LOG_DEBUG,
Z
Zhang Rui 已提交
1746 1747 1748 1749
                   "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,
1750
                   (const char *)av_x_if_null(av_get_pix_fmt_name(frame->format), "none"), is->viddec.pkt_serial);
1751 1752
            avfilter_graph_free(&graph);
            graph = avfilter_graph_alloc();
Z
Zhang Rui 已提交
1753 1754
            if ((ret = configure_video_filters(ffp, graph, is, ffp->vfilters_list ? ffp->vfilters_list[is->vfilter_idx] : NULL, frame)) < 0) {
                // FIXME: post error
Z
Zhang Rui 已提交
1755
                SDL_UnlockMutex(ffp->vf_mutex);
1756 1757
                goto the_end;
            }
Z
Zhang Rui 已提交
1758
            filt_in  = is->in_video_filter;
1759 1760 1761 1762
            filt_out = is->out_video_filter;
            last_w = frame->width;
            last_h = frame->height;
            last_format = frame->format;
1763
            last_serial = is->viddec.pkt_serial;
Z
Zhang Rui 已提交
1764
            last_vfilter_idx = is->vfilter_idx;
Z
Zhang Rui 已提交
1765
            frame_rate = filt_out->inputs[0]->frame_rate;
Z
Zhang Rui 已提交
1766
            SDL_UnlockMutex(ffp->vf_mutex);
1767 1768
        }

Z
Zhang Rui 已提交
1769 1770 1771
        ret = av_buffersrc_add_frame(filt_in, frame);
        if (ret < 0)
            goto the_end;
1772 1773

        while (ret >= 0) {
Z
Zhang Rui 已提交
1774
            is->frame_last_returned_time = av_gettime_relative() / 1000000.0;
1775

Z
Zhang Rui 已提交
1776
            ret = av_buffersink_get_frame_flags(filt_out, frame, 0);
1777
            if (ret < 0) {
1778
                if (ret == AVERROR_EOF)
Z
Zhang Rui 已提交
1779
                    is->viddec.finished = is->viddec.pkt_serial;
1780 1781 1782 1783
                ret = 0;
                break;
            }

Z
Zhang Rui 已提交
1784
            is->frame_last_filter_delay = av_gettime_relative() / 1000000.0 - is->frame_last_returned_time;
1785
            if (fabs(is->frame_last_filter_delay) > AV_NOSYNC_THRESHOLD / 10.0)
Z
Zhang Rui 已提交
1786
                is->frame_last_filter_delay = 0;
Z
Zhang Rui 已提交
1787 1788 1789 1790
            tb = filt_out->inputs[0]->time_base;
#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);
1791
            ret = queue_picture(ffp, frame, pts, duration, av_frame_get_pkt_pos(frame), is->viddec.pkt_serial);
Z
Zhang Rui 已提交
1792
            av_frame_unref(frame);
Z
Zhang Rui 已提交
1793
#if CONFIG_AVFILTER
1794 1795 1796 1797 1798 1799
        }
#endif

        if (ret < 0)
            goto the_end;
    }
Z
Zhang Rui 已提交
1800
 the_end:
1801 1802 1803
#if CONFIG_AVFILTER
    avfilter_graph_free(&graph);
#endif
Z
Zhang Rui 已提交
1804
    av_frame_free(&frame);
1805 1806 1807
    return 0;
}

Z
Zhang Rui 已提交
1808 1809 1810
static int video_thread(void *arg)
{
    FFPlayer *ffp = (FFPlayer *)arg;
1811
    int       ret = 0;
Z
Zhang Rui 已提交
1812

1813 1814 1815
    if (ffp->node_vdec) {
        ret = ffpipenode_run_sync(ffp->node_vdec);
    }
Z
Zhang Rui 已提交
1816 1817 1818
    return ret;
}

Z
Zhang Rui 已提交
1819
// FFP_MERGE: subtitle_thread
1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850

/* copy samples for viewing in editor window */
static void update_sample_display(VideoState *is, short *samples, int samples_size)
{
    int size, len;

    size = samples_size / sizeof(short);
    while (size > 0) {
        len = SAMPLE_ARRAY_SIZE - is->sample_array_index;
        if (len > size)
            len = size;
        memcpy(is->sample_array + is->sample_array_index, samples, len * sizeof(short));
        samples += len;
        is->sample_array_index += len;
        if (is->sample_array_index >= SAMPLE_ARRAY_SIZE)
            is->sample_array_index = 0;
        size -= len;
    }
}

/* return the wanted number of samples to get better sync if sync_type is video
 * or external master clock */
static int synchronize_audio(VideoState *is, int nb_samples)
{
    int wanted_nb_samples = nb_samples;

    /* if not master, then we try to remove or add samples to correct the clock */
    if (get_master_sync_type(is) != AV_SYNC_AUDIO_MASTER) {
        double diff, avg_diff;
        int min_nb_samples, max_nb_samples;

Z
Zhang Rui 已提交
1851
        diff = get_clock(&is->audclk) - get_master_clock(is);
1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862

        if (!isnan(diff) && fabs(diff) < AV_NOSYNC_THRESHOLD) {
            is->audio_diff_cum = diff + is->audio_diff_avg_coef * is->audio_diff_cum;
            if (is->audio_diff_avg_count < AUDIO_DIFF_AVG_NB) {
                /* not enough measures to have a correct estimate */
                is->audio_diff_avg_count++;
            } else {
                /* estimate the A-V difference */
                avg_diff = is->audio_diff_cum * (1.0 - is->audio_diff_avg_coef);

                if (fabs(avg_diff) >= is->audio_diff_threshold) {
Z
Zhang Rui 已提交
1863
                    wanted_nb_samples = nb_samples + (int)(diff * is->audio_src.freq);
1864 1865
                    min_nb_samples = ((nb_samples * (100 - SAMPLE_CORRECTION_PERCENT_MAX) / 100));
                    max_nb_samples = ((nb_samples * (100 + SAMPLE_CORRECTION_PERCENT_MAX) / 100));
1866
                    wanted_nb_samples = av_clip(wanted_nb_samples, min_nb_samples, max_nb_samples);
1867
                }
1868
                av_log(NULL, AV_LOG_TRACE, "diff=%f adiff=%f sample_diff=%d apts=%0.3f %f\n",
Z
Zhang Rui 已提交
1869 1870
                        diff, avg_diff, wanted_nb_samples - nb_samples,
                        is->audio_clock, is->audio_diff_threshold);
1871 1872 1873
            }
        } else {
            /* too big difference : may be initial PTS errors, so
Z
Zhang Rui 已提交
1874
               reset A-V filter */
1875
            is->audio_diff_avg_count = 0;
Z
Zhang Rui 已提交
1876
            is->audio_diff_cum       = 0;
1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889
        }
    }

    return wanted_nb_samples;
}

/**
 * Decode one audio frame and return its uncompressed size.
 *
 * The processed audio frame is decoded, converted if required, and
 * stored in is->audio_buf, with size in bytes given by the return
 * value.
 */
Z
Zhang Rui 已提交
1890
static int audio_decode_frame(FFPlayer *ffp)
1891
{
Z
Zhang Rui 已提交
1892
    VideoState *is = ffp->is;
1893
    int data_size, resampled_data_size;
1894 1895 1896
    int64_t dec_channel_layout;
    av_unused double audio_clock0;
    int wanted_nb_samples;
1897
    Frame *af;
1898

1899
    if (is->paused || is->step)
1900
        return -1;
1901

Z
Zhang Rui 已提交
1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916
    if (ffp->sync_av_start &&                       /* sync enabled */
        is->video_st &&                             /* has video stream */
        !is->viddec.first_frame_decoded &&          /* not hot */
        is->viddec.finished != is->videoq.serial) { /* not finished */
        /* waiting for first video frame */
        Uint64 now = SDL_GetTickHR();
        if (now < is->viddec.first_frame_decoded_time ||
            now > is->viddec.first_frame_decoded_time + 2000) {
            is->viddec.first_frame_decoded = 1;
        } else {
            /* video pipeline is not ready yet */
            return -1;
        }
    }

1917
    do {
1918 1919 1920 1921 1922 1923 1924
#if defined(_WIN32)
        while (frame_queue_nb_remaining(&is->sampq) == 0) {
            if ((av_gettime_relative() - audio_callback_time) > 1000000LL * is->audio_hw_buf_size / is->audio_tgt.bytes_per_sec / 2)
                return -1;
            av_usleep (1000);
        }
#endif
1925 1926 1927 1928
        if (!(af = frame_queue_peek_readable(&is->sampq)))
            return -1;
        frame_queue_next(&is->sampq);
    } while (af->serial != is->audioq.serial);
Z
Zhang Rui 已提交
1929

Z
Zhang Rui 已提交
1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952
    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);
1953
            swr_free(&is->swr_ctx);
Z
Zhang Rui 已提交
1954
            return -1;
1955
        }
Z
Zhang Rui 已提交
1956 1957 1958 1959 1960
        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;
    }
1961

Z
Zhang Rui 已提交
1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975
    if (is->swr_ctx) {
        const uint8_t **in = (const uint8_t **)af->frame->extended_data;
        uint8_t **out = &is->audio_buf1;
        int out_count = (int)((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");
1976 1977 1978
                return -1;
            }
        }
Z
Zhang Rui 已提交
1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997
        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 (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;
    }
1998

Z
Zhang Rui 已提交
1999 2000 2001 2002 2003 2004 2005
    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;
2006
#ifdef FFP_SHOW_AUDIO_DELAY
Z
Zhang Rui 已提交
2007 2008 2009 2010 2011 2012 2013
    {
        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;
    }
2014
#endif
2015 2016 2017 2018 2019 2020 2021 2022 2023
    if (!is->auddec.first_frame_decoded) {
        ALOGD("avcodec/Audio: first frame decoded\n");
        is->auddec.first_frame_decoded_time = SDL_GetTickHR();
        is->auddec.first_frame_decoded = 1;
    }
    if (!ffp->first_audio_frame_rendered) {
        ffp->first_audio_frame_rendered = 1;
        ffp_notify_msg1(ffp, FFP_MSG_AUDIO_RENDERING_START);
    }
2024
    return resampled_data_size;
2025 2026 2027 2028 2029 2030
}

/* prepare a new audio buffer */
static void sdl_audio_callback(void *opaque, Uint8 *stream, int len)
{
    FFPlayer *ffp = opaque;
2031
    VideoState *is = ffp->is;
2032
    int audio_size, len1;
2033 2034 2035 2036
    if (!ffp || !is) {
        memset(stream, 0, len);
        return;
    }
2037

Z
Zhang Rui 已提交
2038
    ffp->audio_callback_time = av_gettime_relative();
2039

Z
Zhang Rui 已提交
2040 2041 2042 2043 2044
    if (ffp->pf_playback_rate_changed) {
        ffp->pf_playback_rate_changed = 0;
        SDL_AoutSetPlaybackRate(ffp->aout, ffp->pf_playback_rate);
    }

2045 2046
    while (len > 0) {
        if (is->audio_buf_index >= is->audio_buf_size) {
Z
Zhang Rui 已提交
2047
           audio_size = audio_decode_frame(ffp);
Z
Zhang Rui 已提交
2048
           if (audio_size < 0) {
2049
                /* if error, just output silence */
Z
Zhang Rui 已提交
2050
               is->audio_buf      = is->silence_buf;
Z
Zhang Rui 已提交
2051
               is->audio_buf_size = sizeof(is->silence_buf) / is->audio_tgt.frame_size * is->audio_tgt.frame_size;
Z
Zhang Rui 已提交
2052 2053 2054 2055 2056 2057
           } else {
               if (is->show_mode != SHOW_MODE_VIDEO)
                   update_sample_display(is, (int16_t *)is->audio_buf, audio_size);
               is->audio_buf_size = audio_size;
           }
           is->audio_buf_index = 0;
2058
        }
2059
        if (is->auddec.pkt_serial != is->audioq.serial) {
2060 2061
            is->audio_buf_index = is->audio_buf_size;
            memset(stream, 0, len);
Z
Zhang Rui 已提交
2062 2063
            // stream += len;
            // len = 0;
2064 2065 2066
            SDL_AoutFlushAudio(ffp->aout);
            break;
        }
2067 2068 2069
        len1 = is->audio_buf_size - is->audio_buf_index;
        if (len1 > len)
            len1 = len;
2070 2071 2072 2073 2074 2075 2076
        if (!is->muted && is->audio_volume == SDL_MIX_MAXVOLUME)
            memcpy(stream, (uint8_t *)is->audio_buf + is->audio_buf_index, len1);
        else {
            memset(stream, is->silence_buf[0], len1);
            if (!is->muted)
                SDL_MixAudio(stream, (uint8_t *)is->audio_buf + is->audio_buf_index, len1, is->audio_volume);
        }
2077 2078 2079 2080 2081 2082
        len -= len1;
        stream += len1;
        is->audio_buf_index += len1;
    }
    is->audio_write_buf_size = is->audio_buf_size - is->audio_buf_index;
    /* Let's assume the audio driver that is used by SDL has two periods. */
Z
Zhang Rui 已提交
2083
    if (!isnan(is->audio_clock)) {
2084
        set_clock_at(&is->audclk, is->audio_clock - (double)(is->audio_write_buf_size) / is->audio_tgt.bytes_per_sec - SDL_AoutGetLatencySeconds(ffp->aout), is->audio_clock_serial, ffp->audio_callback_time / 1000000.0);
Z
Zhang Rui 已提交
2085 2086
        sync_clock_to_slave(&is->extclk, &is->audclk);
    }
2087 2088
}

2089
static int audio_open(FFPlayer *opaque, int64_t wanted_channel_layout, int wanted_nb_channels, int wanted_sample_rate, struct AudioParams *audio_hw_params)
2090
{
Z
Zhang Rui 已提交
2091
    FFPlayer *ffp = opaque;
2092
    VideoState *is = ffp->is;
2093 2094
    SDL_AudioSpec wanted_spec, spec;
    const char *env;
2095
    static const int next_nb_channels[] = {0, 0, 1, 6, 2, 6, 4, 6};
Z
Zhang Rui 已提交
2096 2097 2098
#ifdef FFP_MERGE
    static const int next_sample_rates[] = {0, 44100, 48000, 96000, 192000};
#endif
Z
Zhang Rui 已提交
2099
    static const int next_sample_rates[] = {0, 44100, 48000};
Z
Zhang Rui 已提交
2100
    int next_sample_rate_idx = FF_ARRAY_ELEMS(next_sample_rates) - 1;
2101 2102 2103 2104 2105 2106 2107 2108 2109 2110

    env = SDL_getenv("SDL_AUDIO_CHANNELS");
    if (env) {
        wanted_nb_channels = atoi(env);
        wanted_channel_layout = av_get_default_channel_layout(wanted_nb_channels);
    }
    if (!wanted_channel_layout || wanted_nb_channels != av_get_channel_layout_nb_channels(wanted_channel_layout)) {
        wanted_channel_layout = av_get_default_channel_layout(wanted_nb_channels);
        wanted_channel_layout &= ~AV_CH_LAYOUT_STEREO_DOWNMIX;
    }
Z
Zhang Rui 已提交
2111 2112
    wanted_nb_channels = av_get_channel_layout_nb_channels(wanted_channel_layout);
    wanted_spec.channels = wanted_nb_channels;
2113 2114
    wanted_spec.freq = wanted_sample_rate;
    if (wanted_spec.freq <= 0 || wanted_spec.channels <= 0) {
Z
Zhang Rui 已提交
2115
        av_log(NULL, AV_LOG_ERROR, "Invalid sample rate or channel count!\n");
2116 2117
        return -1;
    }
Z
Zhang Rui 已提交
2118 2119
    while (next_sample_rate_idx && next_sample_rates[next_sample_rate_idx] >= wanted_spec.freq)
        next_sample_rate_idx--;
2120 2121
    wanted_spec.format = AUDIO_S16SYS;
    wanted_spec.silence = 0;
Z
Zhang Rui 已提交
2122
    wanted_spec.samples = FFMAX(SDL_AUDIO_MIN_BUFFER_SIZE, 2 << av_log2(wanted_spec.freq / SDL_AUDIO_MAX_CALLBACKS_PER_SEC));
2123 2124
    wanted_spec.callback = sdl_audio_callback;
    wanted_spec.userdata = opaque;
Z
Zhang Rui 已提交
2125
    while (SDL_AoutOpenAudio(ffp->aout, &wanted_spec, &spec) < 0) {
2126 2127 2128
        /* avoid infinity loop on exit. --by bbcallen */
        if (is->abort_request)
            return -1;
Z
Zhang Rui 已提交
2129 2130
        av_log(NULL, AV_LOG_WARNING, "SDL_OpenAudio (%d channels, %d Hz): %s\n",
               wanted_spec.channels, wanted_spec.freq, SDL_GetError());
2131 2132
        wanted_spec.channels = next_nb_channels[FFMIN(7, wanted_spec.channels)];
        if (!wanted_spec.channels) {
Z
Zhang Rui 已提交
2133 2134 2135 2136 2137 2138 2139
            wanted_spec.freq = next_sample_rates[next_sample_rate_idx--];
            wanted_spec.channels = wanted_nb_channels;
            if (!wanted_spec.freq) {
                av_log(NULL, AV_LOG_ERROR,
                       "No more combinations to try, audio open failed\n");
                return -1;
            }
2140 2141 2142 2143
        }
        wanted_channel_layout = av_get_default_channel_layout(wanted_spec.channels);
    }
    if (spec.format != AUDIO_S16SYS) {
Z
Zhang Rui 已提交
2144 2145
        av_log(NULL, AV_LOG_ERROR,
               "SDL advised audio format %d is not supported!\n", spec.format);
2146 2147 2148 2149 2150
        return -1;
    }
    if (spec.channels != wanted_spec.channels) {
        wanted_channel_layout = av_get_default_channel_layout(spec.channels);
        if (!wanted_channel_layout) {
Z
Zhang Rui 已提交
2151 2152
            av_log(NULL, AV_LOG_ERROR,
                   "SDL advised channel count %d is not supported!\n", spec.channels);
2153 2154 2155 2156 2157 2158 2159
            return -1;
        }
    }

    audio_hw_params->fmt = AV_SAMPLE_FMT_S16;
    audio_hw_params->freq = spec.freq;
    audio_hw_params->channel_layout = wanted_channel_layout;
Z
Zhang Rui 已提交
2160
    audio_hw_params->channels =  spec.channels;
Z
Zhang Rui 已提交
2161 2162 2163 2164 2165 2166
    audio_hw_params->frame_size = av_samples_get_buffer_size(NULL, audio_hw_params->channels, 1, audio_hw_params->fmt, 1);
    audio_hw_params->bytes_per_sec = av_samples_get_buffer_size(NULL, audio_hw_params->channels, audio_hw_params->freq, audio_hw_params->fmt, 1);
    if (audio_hw_params->bytes_per_sec <= 0 || audio_hw_params->frame_size <= 0) {
        av_log(NULL, AV_LOG_ERROR, "av_samples_get_buffer_size failed\n");
        return -1;
    }
2167 2168

    SDL_AoutSetDefaultLatencySeconds(ffp->aout, ((double)(2 * spec.size)) / audio_hw_params->bytes_per_sec);
2169 2170 2171 2172 2173 2174
    return spec.size;
}

/* open a given stream. Return 0 if OK */
static int stream_component_open(FFPlayer *ffp, int stream_index)
{
2175
    VideoState *is = ffp->is;
2176 2177 2178 2179 2180 2181
    AVFormatContext *ic = is->ic;
    AVCodecContext *avctx;
    AVCodec *codec;
    const char *forced_codec_name = NULL;
    AVDictionary *opts;
    AVDictionaryEntry *t = NULL;
Z
Zhang Rui 已提交
2182 2183
    int sample_rate, nb_channels;
    int64_t channel_layout;
2184
    int ret = 0;
2185
    int stream_lowres = ffp->lowres;
2186 2187 2188 2189 2190 2191 2192

    if (stream_index < 0 || stream_index >= ic->nb_streams)
        return -1;
    avctx = ic->streams[stream_index]->codec;

    codec = avcodec_find_decoder(avctx->codec_id);

Z
Zhang Rui 已提交
2193
    switch (avctx->codec_type) {
Z
Zhang Rui 已提交
2194 2195 2196 2197
        case AVMEDIA_TYPE_AUDIO   : is->last_audio_stream    = stream_index; forced_codec_name = ffp->audio_codec_name; break;
        // FFP_MERGE: case AVMEDIA_TYPE_SUBTITLE:
        case AVMEDIA_TYPE_VIDEO   : is->last_video_stream    = stream_index; forced_codec_name = ffp->video_codec_name; break;
        default: break;
2198 2199 2200 2201
    }
    if (forced_codec_name)
        codec = avcodec_find_decoder_by_name(forced_codec_name);
    if (!codec) {
Z
Zhang Rui 已提交
2202 2203 2204 2205
        if (forced_codec_name) av_log(NULL, AV_LOG_WARNING,
                                      "No codec could be found with name '%s'\n", forced_codec_name);
        else                   av_log(NULL, AV_LOG_WARNING,
                                      "No codec could be found with id %d\n", avctx->codec_id);
2206 2207 2208 2209
        return -1;
    }

    avctx->codec_id = codec->id;
2210
    if(stream_lowres > av_codec_get_max_lowres(codec)){
2211
        av_log(avctx, AV_LOG_WARNING, "The maximum value for lowres supported by the decoder is %d\n",
2212
                av_codec_get_max_lowres(codec));
2213
        stream_lowres = av_codec_get_max_lowres(codec);
2214
    }
2215
    av_codec_set_lowres(avctx, stream_lowres);
2216

2217
#if FF_API_EMU_EDGE
2218
    if(stream_lowres) avctx->flags |= CODEC_FLAG_EMU_EDGE;
2219
#endif
2220 2221
    if (ffp->fast)
        avctx->flags2 |= AV_CODEC_FLAG2_FAST;
2222
#if FF_API_EMU_EDGE
2223
    if(codec->capabilities & AV_CODEC_CAP_DR1)
2224
        avctx->flags |= CODEC_FLAG_EMU_EDGE;
2225
#endif
2226 2227 2228 2229

    opts = filter_codec_opts(ffp->codec_opts, avctx->codec_id, ic, ic->streams[stream_index], codec);
    if (!av_dict_get(opts, "threads", NULL, 0))
        av_dict_set(&opts, "threads", "auto", 0);
2230
    if (stream_lowres)
Z
Zhang Rui 已提交
2231
        av_dict_set_int(&opts, "lowres", stream_lowres, 0);
Z
Zhang Rui 已提交
2232 2233
    if (avctx->codec_type == AVMEDIA_TYPE_VIDEO || avctx->codec_type == AVMEDIA_TYPE_AUDIO)
        av_dict_set(&opts, "refcounted_frames", "1", 0);
2234 2235 2236
    if ((ret = avcodec_open2(avctx, codec, &opts)) < 0) {
        goto fail;
    }
2237 2238
    if ((t = av_dict_get(opts, "", NULL, AV_DICT_IGNORE_SUFFIX))) {
        av_log(NULL, AV_LOG_ERROR, "Option %s not found.\n", t->key);
B
bbcallen 已提交
2239
#ifdef FFP_MERGE
Z
Zhang Rui 已提交
2240
        ret =  AVERROR_OPTION_NOT_FOUND;
2241
        goto fail;
B
bbcallen 已提交
2242
#endif
2243 2244
    }

2245
    is->eof = 0;
2246 2247 2248
    ic->streams[stream_index]->discard = AVDISCARD_DEFAULT;
    switch (avctx->codec_type) {
    case AVMEDIA_TYPE_AUDIO:
Z
Zhang Rui 已提交
2249 2250 2251 2252 2253 2254 2255 2256
#if CONFIG_AVFILTER
        {
            AVFilterLink *link;

            is->audio_filter_src.freq           = avctx->sample_rate;
            is->audio_filter_src.channels       = avctx->channels;
            is->audio_filter_src.channel_layout = get_valid_channel_layout(avctx->channel_layout, avctx->channels);
            is->audio_filter_src.fmt            = avctx->sample_fmt;
Z
Zhang Rui 已提交
2257 2258 2259
            SDL_LockMutex(ffp->af_mutex);
            if ((ret = configure_audio_filters(ffp, ffp->afilters, 0)) < 0) {
                SDL_UnlockMutex(ffp->af_mutex);
2260
                goto fail;
Z
Zhang Rui 已提交
2261 2262 2263
            }
            ffp->af_changed = 0;
            SDL_UnlockMutex(ffp->af_mutex);
Z
Zhang Rui 已提交
2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276
            link = is->out_audio_filter->inputs[0];
            sample_rate    = link->sample_rate;
            nb_channels    = link->channels;
            channel_layout = link->channel_layout;
        }
#else
        sample_rate    = avctx->sample_rate;
        nb_channels    = avctx->channels;
        channel_layout = avctx->channel_layout;
#endif

        /* prepare audio output */
        if ((ret = audio_open(ffp, channel_layout, nb_channels, sample_rate, &is->audio_tgt)) < 0)
2277
            goto fail;
Z
Zhang Rui 已提交
2278
        ffp_set_audio_codec_info(ffp, AVCODEC_MODULE_NAME, avcodec_get_name(avctx->codec_id));
Z
Zhang Rui 已提交
2279 2280
        is->audio_hw_buf_size = ret;
        is->audio_src = is->audio_tgt;
Z
Zhang Rui 已提交
2281
        is->audio_buf_size  = 0;
2282 2283 2284
        is->audio_buf_index = 0;

        /* init averaging filter */
Z
Zhang Rui 已提交
2285
        is->audio_diff_avg_coef  = exp(log(0.01) / AUDIO_DIFF_AVG_NB);
2286 2287
        is->audio_diff_avg_count = 0;
        /* since we do not have a precise anough audio fifo fullness,
Z
Zhang Rui 已提交
2288
           we correct audio sync only if larger than this threshold */
Z
Zhang Rui 已提交
2289
        is->audio_diff_threshold = 2.0 * is->audio_hw_buf_size / is->audio_tgt.bytes_per_sec;
2290

Z
Zhang Rui 已提交
2291 2292 2293
        is->audio_stream = stream_index;
        is->audio_st = ic->streams[stream_index];

2294
        decoder_init(&is->auddec, avctx, &is->audioq, is->continue_read_thread);
2295 2296 2297 2298
        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;
        }
2299 2300
        if ((ret = decoder_start(&is->auddec, audio_thread, ffp, "ff_audio_dec")) < 0)
            goto fail;
Z
Zhang Rui 已提交
2301
        SDL_AoutPauseAudio(ffp->aout, 0);
2302 2303 2304 2305
        break;
    case AVMEDIA_TYPE_VIDEO:
        is->video_stream = stream_index;
        is->video_st = ic->streams[stream_index];
Z
Zhang Rui 已提交
2306

2307 2308 2309 2310 2311
#ifdef FFP_MERGE
        is->viddec_width  = avctx->width;
        is->viddec_height = avctx->height;
#endif

2312
        decoder_init(&is->viddec, avctx, &is->videoq, is->continue_read_thread);
2313 2314 2315
        ffp->node_vdec = ffpipeline_open_video_decoder(ffp->pipeline, ffp);
        if (!ffp->node_vdec)
            goto fail;
2316 2317
        if ((ret = decoder_start(&is->viddec, video_thread, ffp, "ff_video_dec")) < 0)
            goto fail;
Z
Zhang Rui 已提交
2318
        is->queue_attachments_req = 1;
2319 2320 2321

        if(is->video_st->avg_frame_rate.den && is->video_st->avg_frame_rate.num) {
            double fps = av_q2d(is->video_st->avg_frame_rate);
Z
Zhang Rui 已提交
2322
            SDL_ProfilerReset(&is->viddec.decode_profiler, fps + 0.5);
2323
            if (fps > ffp->max_fps && fps < 130.0) {
2324
                is->is_video_high_fps = 1;
2325
                av_log(ffp, AV_LOG_WARNING, "fps: %lf (too high)\n", fps);
2326
            } else {
2327
                av_log(ffp, AV_LOG_WARNING, "fps: %lf (normal)\n", fps);
2328 2329 2330 2331
            }
        }
        if(is->video_st->r_frame_rate.den && is->video_st->r_frame_rate.num) {
            double tbr = av_q2d(is->video_st->r_frame_rate);
2332
            if (tbr > ffp->max_fps && tbr < 130.0) {
2333
                is->is_video_high_fps = 1;
2334
                av_log(ffp, AV_LOG_WARNING, "fps: %lf (too high)\n", tbr);
2335
            } else {
2336
                av_log(ffp, AV_LOG_WARNING, "fps: %lf (normal)\n", tbr);
2337 2338 2339 2340 2341 2342 2343 2344 2345
            }
        }

        if (is->is_video_high_fps) {
            avctx->skip_frame       = FFMAX(avctx->skip_frame, AVDISCARD_NONREF);
            avctx->skip_loop_filter = FFMAX(avctx->skip_loop_filter, AVDISCARD_NONREF);
            avctx->skip_idct        = FFMAX(avctx->skip_loop_filter, AVDISCARD_NONREF);
        }

2346
        break;
Z
Zhang Rui 已提交
2347
    // FFP_MERGE: case AVMEDIA_TYPE_SUBTITLE:
2348 2349 2350
    default:
        break;
    }
2351 2352 2353 2354
fail:
    av_dict_free(&opts);

    return ret;
2355 2356 2357 2358 2359 2360 2361 2362 2363 2364
}

static int decode_interrupt_cb(void *ctx)
{
    VideoState *is = ctx;
    return is->abort_request;
}

static int is_realtime(AVFormatContext *s)
{
Z
Zhang Rui 已提交
2365 2366 2367 2368
    if(   !strcmp(s->iformat->name, "rtp")
       || !strcmp(s->iformat->name, "rtsp")
       || !strcmp(s->iformat->name, "sdp")
    )
2369 2370
        return 1;

Z
Zhang Rui 已提交
2371 2372 2373 2374
    if(s->pb && (   !strncmp(s->filename, "rtp:", 4)
                 || !strncmp(s->filename, "udp:", 4)
                )
    )
2375 2376 2377 2378 2379 2380 2381 2382
        return 1;
    return 0;
}

/* this thread gets the stream from the disk or the network */
static int read_thread(void *arg)
{
    FFPlayer *ffp = arg;
2383
    VideoState *is = ffp->is;
2384
    AVFormatContext *ic = NULL;
Z
Zhang Rui 已提交
2385
    int err, i, ret __unused;
2386 2387
    int st_index[AVMEDIA_TYPE_NB];
    AVPacket pkt1, *pkt = &pkt1;
Z
Zhang Rui 已提交
2388
    int64_t stream_start_time;
2389
    int completed = 0;
2390 2391 2392 2393 2394
    int pkt_in_play_range = 0;
    AVDictionaryEntry *t;
    AVDictionary **opts;
    int orig_nb_streams;
    SDL_mutex *wait_mutex = SDL_CreateMutex();
2395
    int scan_all_pmts_set = 0;
2396
    int64_t pkt_ts;
2397
    int last_error = 0;
2398
    int64_t prev_io_tick_counter = 0;
Z
Zhang Rui 已提交
2399
    int64_t io_tick_counter = 0;
2400

2401 2402 2403 2404 2405 2406
    if (!wait_mutex) {
        av_log(NULL, AV_LOG_FATAL, "SDL_CreateMutex(): %s\n", SDL_GetError());
        ret = AVERROR(ENOMEM);
        goto fail;
    }

2407 2408 2409
    memset(st_index, -1, sizeof(st_index));
    is->last_video_stream = is->video_stream = -1;
    is->last_audio_stream = is->audio_stream = -1;
Z
Zhang Rui 已提交
2410
#ifdef FFP_MERGE
2411
    is->last_subtitle_stream = is->subtitle_stream = -1;
Z
Zhang Rui 已提交
2412
#endif
2413
    is->eof = 0;
2414 2415

    ic = avformat_alloc_context();
2416 2417 2418 2419 2420
    if (!ic) {
        av_log(NULL, AV_LOG_FATAL, "Could not allocate context.\n");
        ret = AVERROR(ENOMEM);
        goto fail;
    }
2421 2422
    ic->interrupt_callback.callback = decode_interrupt_cb;
    ic->interrupt_callback.opaque = is;
2423 2424 2425 2426
    if (!av_dict_get(ffp->format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE)) {
        av_dict_set(&ffp->format_opts, "scan_all_pmts", "1", AV_DICT_DONT_OVERWRITE);
        scan_all_pmts_set = 1;
    }
2427 2428
    if (av_stristart(is->filename, "rtmp", NULL) ||
        av_stristart(is->filename, "rtsp", NULL)) {
2429
        // There is total different meaning for 'timeout' option in rtmp
Z
Zhang Rui 已提交
2430
        av_log(ffp, AV_LOG_WARNING, "remove 'timeout' option for rtmp.\n");
2431 2432
        av_dict_set(&ffp->format_opts, "timeout", NULL, 0);
    }
Z
Zhang Rui 已提交
2433 2434
    if (ffp->iformat_name)
        is->iformat = av_find_input_format(ffp->iformat_name);
2435 2436 2437 2438 2439 2440
    err = avformat_open_input(&ic, is->filename, is->iformat, &ffp->format_opts);
    if (err < 0) {
        print_error(is->filename, err);
        ret = -1;
        goto fail;
    }
2441 2442 2443
    if (scan_all_pmts_set)
        av_dict_set(&ffp->format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE);

2444 2445
    if ((t = av_dict_get(ffp->format_opts, "", NULL, AV_DICT_IGNORE_SUFFIX))) {
        av_log(NULL, AV_LOG_ERROR, "Option %s not found.\n", t->key);
B
bbcallen 已提交
2446
#ifdef FFP_MERGE
2447 2448
        ret = AVERROR_OPTION_NOT_FOUND;
        goto fail;
B
bbcallen 已提交
2449
#endif
2450 2451 2452 2453 2454 2455
    }
    is->ic = ic;

    if (ffp->genpts)
        ic->flags |= AVFMT_FLAG_GENPTS;

Z
Zhang Rui 已提交
2456 2457
    av_format_inject_global_side_data(ic);

2458 2459 2460 2461
    opts = setup_find_stream_info_opts(ic, ffp->codec_opts);
    orig_nb_streams = ic->nb_streams;

    err = avformat_find_stream_info(ic, opts);
2462 2463 2464 2465 2466

    for (i = 0; i < orig_nb_streams; i++)
        av_dict_free(&opts[i]);
    av_freep(&opts);

2467
    if (err < 0) {
Z
Zhang Rui 已提交
2468 2469
        av_log(NULL, AV_LOG_WARNING,
               "%s: could not find codec parameters\n", is->filename);
2470 2471 2472 2473 2474
        ret = -1;
        goto fail;
    }

    if (ic->pb)
Z
Zhang Rui 已提交
2475
        ic->pb->eof_reached = 0; // FIXME hack, ffplay maybe should not use avio_feof() to test for the end
2476 2477

    if (ffp->seek_by_bytes < 0)
Z
Zhang Rui 已提交
2478
        ffp->seek_by_bytes = !!(ic->iformat->flags & AVFMT_TS_DISCONT) && strcmp("ogg", ic->iformat->name);
2479 2480

    is->max_frame_duration = (ic->iformat->flags & AVFMT_TS_DISCONT) ? 10.0 : 3600.0;
Z
Zhang Rui 已提交
2481
    is->max_frame_duration = 10.0;
2482
    av_log(ffp, AV_LOG_INFO, "max_frame_duration: %.3f\n", is->max_frame_duration);
2483

Z
Zhang Rui 已提交
2484 2485 2486
#ifdef FFP_MERGE
    if (!window_title && (t = av_dict_get(ic->metadata, "title", NULL, 0)))
        window_title = av_asprintf("%s - %s", t->value, input_filename);
Z
Zhang Rui 已提交
2487

Z
Zhang Rui 已提交
2488
#endif
2489 2490 2491 2492 2493 2494 2495 2496 2497 2498
    /* if seeking requested, we execute it */
    if (ffp->start_time != AV_NOPTS_VALUE) {
        int64_t timestamp;

        timestamp = ffp->start_time;
        /* add the stream start time */
        if (ic->start_time != AV_NOPTS_VALUE)
            timestamp += ic->start_time;
        ret = avformat_seek_file(ic, -1, INT64_MIN, timestamp, INT64_MAX, 0);
        if (ret < 0) {
Z
Zhang Rui 已提交
2499
            av_log(NULL, AV_LOG_WARNING, "%s: could not seek to position %0.3f\n",
Z
Zhang Rui 已提交
2500
                    is->filename, (double)timestamp / AV_TIME_BASE);
2501 2502 2503 2504 2505
        }
    }

    is->realtime = is_realtime(ic);

2506 2507 2508
    if (true || ffp->show_status)
        av_dump_format(ic, 0, is->filename, 0);

B
bbcallen 已提交
2509 2510 2511 2512
    int video_stream_count = 0;
    int h264_stream_count = 0;
    int first_h264_stream = -1;
    for (i = 0; i < ic->nb_streams; i++) {
2513 2514 2515 2516 2517 2518 2519 2520
        AVStream *st = ic->streams[i];
        enum AVMediaType type = st->codec->codec_type;
        st->discard = AVDISCARD_ALL;
        if (ffp->wanted_stream_spec[type] && st_index[type] == -1)
            if (avformat_match_stream_specifier(ic, st, ffp->wanted_stream_spec[type]) > 0)
                st_index[type] = i;

        // choose first h264
B
bbcallen 已提交
2521 2522 2523 2524 2525 2526 2527 2528 2529 2530
        AVCodecContext *codec = ic->streams[i]->codec;
        if (codec->codec_type == AVMEDIA_TYPE_VIDEO) {
            video_stream_count++;
            if (codec->codec_id == AV_CODEC_ID_H264) {
                h264_stream_count++;
                if (first_h264_stream < 0)
                    first_h264_stream = i;
            }
        }
    }
2531 2532
    if (video_stream_count > 1 && st_index[AVMEDIA_TYPE_VIDEO] < 0) {
        st_index[AVMEDIA_TYPE_VIDEO] = first_h264_stream;
B
bbcallen 已提交
2533 2534
        av_log(NULL, AV_LOG_WARNING, "multiple video stream found, prefer first h264 stream: %d\n", first_h264_stream);
    }
2535 2536
    if (!ffp->video_disable)
        st_index[AVMEDIA_TYPE_VIDEO] =
Z
Zhang Rui 已提交
2537
            av_find_best_stream(ic, AVMEDIA_TYPE_VIDEO,
2538
                                st_index[AVMEDIA_TYPE_VIDEO], -1, NULL, 0);
2539 2540
    if (!ffp->audio_disable)
        st_index[AVMEDIA_TYPE_AUDIO] =
Z
Zhang Rui 已提交
2541
            av_find_best_stream(ic, AVMEDIA_TYPE_AUDIO,
2542
                                st_index[AVMEDIA_TYPE_AUDIO],
Z
Zhang Rui 已提交
2543 2544 2545
                                st_index[AVMEDIA_TYPE_VIDEO],
                                NULL, 0);
#ifdef FFP_MERGE
2546 2547
    if (!ffp->video_disable && !ffp->subtitle_disable)
        st_index[AVMEDIA_TYPE_SUBTITLE] =
Z
Zhang Rui 已提交
2548
            av_find_best_stream(ic, AVMEDIA_TYPE_SUBTITLE,
2549
                                st_index[AVMEDIA_TYPE_SUBTITLE],
Z
Zhang Rui 已提交
2550 2551 2552
                                (st_index[AVMEDIA_TYPE_AUDIO] >= 0 ?
                                 st_index[AVMEDIA_TYPE_AUDIO] :
                                 st_index[AVMEDIA_TYPE_VIDEO]),
Z
Zhang Rui 已提交
2553
                                NULL, 0);
Z
Zhang Rui 已提交
2554
#endif
2555 2556

    is->show_mode = ffp->show_mode;
Z
Zhang Rui 已提交
2557 2558 2559 2560
#ifdef FFP_MERGE // bbc: dunno if we need this
    if (st_index[AVMEDIA_TYPE_VIDEO] >= 0) {
        AVStream *st = ic->streams[st_index[AVMEDIA_TYPE_VIDEO]];
        AVCodecContext *avctx = st->codec;
Z
Zhang Rui 已提交
2561 2562 2563
        AVRational sar = av_guess_sample_aspect_ratio(ic, st, NULL);
        if (avctx->width)
            set_default_window_size(avctx->width, avctx->height, sar);
Z
Zhang Rui 已提交
2564 2565
    }
#endif
2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578

    /* open the streams */
    if (st_index[AVMEDIA_TYPE_AUDIO] >= 0) {
        stream_component_open(ffp, st_index[AVMEDIA_TYPE_AUDIO]);
    }

    ret = -1;
    if (st_index[AVMEDIA_TYPE_VIDEO] >= 0) {
        ret = stream_component_open(ffp, st_index[AVMEDIA_TYPE_VIDEO]);
    }
    if (is->show_mode == SHOW_MODE_NONE)
        is->show_mode = ret >= 0 ? SHOW_MODE_VIDEO : SHOW_MODE_RDFT;

Z
Zhang Rui 已提交
2579
#ifdef FFP_MERGE
2580 2581 2582
    if (st_index[AVMEDIA_TYPE_SUBTITLE] >= 0) {
        stream_component_open(ffp, st_index[AVMEDIA_TYPE_SUBTITLE]);
    }
Z
Zhang Rui 已提交
2583
#endif
2584
    ijkmeta_set_avformat_context_l(ffp->meta, ic);
Z
Zhang Rui 已提交
2585
    ffp->stat.bit_rate = ic->bit_rate;
2586 2587 2588 2589
    if (st_index[AVMEDIA_TYPE_VIDEO] >= 0)
        ijkmeta_set_int64_l(ffp->meta, IJKM_KEY_VIDEO_STREAM, st_index[AVMEDIA_TYPE_VIDEO]);
    if (st_index[AVMEDIA_TYPE_AUDIO] >= 0)
        ijkmeta_set_int64_l(ffp->meta, IJKM_KEY_AUDIO_STREAM, st_index[AVMEDIA_TYPE_AUDIO]);
2590 2591

    if (is->video_stream < 0 && is->audio_stream < 0) {
2592 2593
        av_log(NULL, AV_LOG_FATAL, "Failed to open file '%s' or configure filtergraph\n",
               is->filename);
2594 2595 2596
        ret = -1;
        goto fail;
    }
2597 2598 2599 2600 2601 2602 2603 2604 2605
    if (is->audio_stream >= 0) {
        is->audioq.is_buffer_indicator = 1;
        is->buffer_indicator_queue = &is->audioq;
    } else if (is->video_stream >= 0) {
        is->videoq.is_buffer_indicator = 1;
        is->buffer_indicator_queue = &is->videoq;
    } else {
        assert("invalid streams");
    }
2606 2607 2608 2609

    if (ffp->infinite_buffer < 0 && is->realtime)
        ffp->infinite_buffer = 1;

Z
Zhang Rui 已提交
2610
    if (!ffp->start_on_prepared)
2611
        toggle_pause(ffp, 1);
2612 2613
    if (is->video_st && is->video_st->codec) {
        AVCodecContext *avctx = is->video_st->codec;
2614 2615
        ffp_notify_msg3(ffp, FFP_MSG_VIDEO_SIZE_CHANGED, avctx->width, avctx->height);
        ffp_notify_msg3(ffp, FFP_MSG_SAR_CHANGED, avctx->sample_aspect_ratio.num, avctx->sample_aspect_ratio.den);
2616
    }
2617 2618
    ffp->prepared = true;
    ffp_notify_msg1(ffp, FFP_MSG_PREPARED);
Z
Zhang Rui 已提交
2619
    if (!ffp->start_on_prepared) {
2620
        while (is->pause_req && !is->abort_request) {
2621 2622 2623
            SDL_Delay(100);
        }
    }
Z
Zhang Rui 已提交
2624
    if (ffp->auto_resume) {
2625
        ffp_notify_msg1(ffp, FFP_REQ_START);
Z
Zhang Rui 已提交
2626
        ffp->auto_resume = 0;
2627
    }
Z
Zhang Rui 已提交
2628

2629 2630 2631
    for (;;) {
        if (is->abort_request)
            break;
Z
Zhang Rui 已提交
2632
#ifdef FFP_MERGE
2633 2634 2635 2636 2637 2638 2639
        if (is->paused != is->last_paused) {
            is->last_paused = is->paused;
            if (is->paused)
                is->read_pause_return = av_read_pause(ic);
            else
                av_read_play(ic);
        }
Z
Zhang Rui 已提交
2640
#endif
Z
Zhang Rui 已提交
2641
#if CONFIG_RTSP_DEMUXER || CONFIG_MMSH_PROTOCOL
2642
        if (is->paused &&
Z
Zhang Rui 已提交
2643 2644
                (!strcmp(ic->iformat->name, "rtsp") ||
                 (ic->pb && !strncmp(ffp->input_filename, "mmsh:", 5)))) {
2645 2646 2647 2648 2649
            /* wait 10 ms to avoid trying to get another packet */
            /* XXX: horrible */
            SDL_Delay(10);
            continue;
        }
Z
Zhang Rui 已提交
2650
#endif
2651 2652
        if (is->seek_req) {
            int64_t seek_target = is->seek_pos;
Z
Zhang Rui 已提交
2653 2654
            int64_t seek_min    = is->seek_rel > 0 ? seek_target - is->seek_rel + 2: INT64_MIN;
            int64_t seek_max    = is->seek_rel < 0 ? seek_target - is->seek_rel - 2: INT64_MAX;
2655 2656 2657
// FIXME the +-2 is due to rounding being not done in the correct direction in generation
//      of the seek_pos/seek_rel variables

B
bbcallen 已提交
2658
            ffp_toggle_buffering(ffp, 1);
2659 2660
            ret = avformat_seek_file(is->ic, -1, seek_min, seek_target, seek_max, is->seek_flags);
            if (ret < 0) {
Z
Zhang Rui 已提交
2661 2662
                av_log(NULL, AV_LOG_ERROR,
                       "%s: error while seeking\n", is->ic->filename);
2663
                ffp_notify_msg1(ffp, FFP_MSG_SEEK_COMPLETE);
2664 2665 2666 2667 2668
            } else {
                if (is->audio_stream >= 0) {
                    packet_queue_flush(&is->audioq);
                    packet_queue_put(&is->audioq, &flush_pkt);
                }
Z
Zhang Rui 已提交
2669
#ifdef FFP_MERGE
2670 2671 2672 2673
                if (is->subtitle_stream >= 0) {
                    packet_queue_flush(&is->subtitleq);
                    packet_queue_put(&is->subtitleq, &flush_pkt);
                }
Z
Zhang Rui 已提交
2674
#endif
2675
                if (is->video_stream >= 0) {
2676 2677 2678
                    if (ffp->node_vdec) {
                        ffpipenode_flush(ffp->node_vdec);
                    }
2679 2680 2681 2682
                    packet_queue_flush(&is->videoq);
                    packet_queue_put(&is->videoq, &flush_pkt);
                }
                if (is->seek_flags & AVSEEK_FLAG_BYTE) {
Z
Zhang Rui 已提交
2683
                   set_clock(&is->extclk, NAN, 0);
2684
                } else {
Z
Zhang Rui 已提交
2685
                   set_clock(&is->extclk, seek_target / (double)AV_TIME_BASE, 0);
2686 2687
                }
            }
Z
Zhang Rui 已提交
2688
            ffp->dcc.current_high_water_mark_in_ms = ffp->dcc.first_high_water_mark_in_ms;
2689
            is->seek_req = 0;
Z
Zhang Rui 已提交
2690
            is->queue_attachments_req = 1;
2691
            is->eof = 0;
Z
Zhang Rui 已提交
2692 2693 2694 2695
#ifdef FFP_MERGE
            if (is->paused)
                step_to_next_frame(is);
#endif
B
bbcallen 已提交
2696
            completed = 0;
Z
Zhang Rui 已提交
2697
            SDL_LockMutex(ffp->is->play_mutex);
Z
Zhang Rui 已提交
2698
            if (ffp->auto_resume) {
2699
                is->pause_req = 0;
2700 2701
                if (ffp->packet_buffering)
                    is->buffering_on = 1;
Z
Zhang Rui 已提交
2702
                ffp->auto_resume = 0;
2703 2704 2705
                stream_update_pause_l(ffp);
            }
            if (is->pause_req)
2706
                step_to_next_frame_l(ffp);
Z
Zhang Rui 已提交
2707
            SDL_UnlockMutex(ffp->is->play_mutex);
2708
            ffp_notify_msg1(ffp, FFP_MSG_SEEK_COMPLETE);
B
bbcallen 已提交
2709
            ffp_toggle_buffering(ffp, 1);
2710 2711
        }
        if (is->queue_attachments_req) {
Z
Zhang Rui 已提交
2712 2713 2714 2715 2716
            if (is->video_st && (is->video_st->disposition & AV_DISPOSITION_ATTACHED_PIC)) {
                AVPacket copy;
                if ((ret = av_copy_packet(&copy, &is->video_st->attached_pic)) < 0)
                    goto fail;
                packet_queue_put(&is->videoq, &copy);
2717
                packet_queue_put_nullpacket(&is->videoq, is->video_stream);
Z
Zhang Rui 已提交
2718
            }
2719 2720 2721 2722
            is->queue_attachments_req = 0;
        }

        /* if the queue are full, no need to read more */
2723
        if (ffp->infinite_buffer<1 && !is->seek_req &&
Z
Zhang Rui 已提交
2724 2725
#ifdef FFP_MERGE
              (is->audioq.size + is->videoq.size + is->subtitleq.size > MAX_QUEUE_SIZE
Z
Zhang Rui 已提交
2726
#else
Z
Zhang Rui 已提交
2727
              (((is->audioq.size + is->videoq.size > ffp->dcc.max_buffer_size)
Z
Zhang Rui 已提交
2728 2729
                 && (is->audioq.nb_packets > MIN_MIN_FRAMES || is->audio_stream < 0 || is->audioq.abort_request)
                 && (is->videoq.nb_packets > MIN_MIN_FRAMES || is->video_stream < 0 || is->videoq.abort_request)
2730
                )
Z
Zhang Rui 已提交
2731 2732
#endif
            || (   (is->audioq   .nb_packets > MIN_FRAMES || is->audio_stream < 0 || is->audioq.abort_request)
Z
Zhang Rui 已提交
2733 2734
                && (is->videoq   .nb_packets > MIN_FRAMES || is->video_stream < 0 || is->videoq.abort_request
                    || (is->video_st->disposition & AV_DISPOSITION_ATTACHED_PIC))
Z
Zhang Rui 已提交
2735
#ifdef FFP_MERGE
Z
Zhang Rui 已提交
2736
                && (is->subtitleq.nb_packets > MIN_FRAMES || is->subtitle_stream < 0 || is->subtitleq.abort_request)))) {
Z
Zhang Rui 已提交
2737 2738 2739
#else
                ))) {
#endif
2740
            if (!is->eof) {
Z
Zhang Rui 已提交
2741
                ffp_toggle_buffering(ffp, 0);
Z
Zhang Rui 已提交
2742
            }
2743 2744 2745 2746 2747 2748
            /* wait 10 ms */
            SDL_LockMutex(wait_mutex);
            SDL_CondWaitTimeout(is->continue_read_thread, wait_mutex, 10);
            SDL_UnlockMutex(wait_mutex);
            continue;
        }
B
bbcallen 已提交
2749
        if ((!is->paused || completed) &&
2750
            (!is->audio_st || (is->auddec.finished == is->audioq.serial && frame_queue_nb_remaining(&is->sampq) == 0)) &&
2751
            (!is->video_st || (is->viddec.finished == is->videoq.serial && frame_queue_nb_remaining(&is->pictq) == 0))) {
2752 2753 2754 2755 2756 2757
            if (ffp->loop != 1 && (!ffp->loop || --ffp->loop)) {
                stream_seek(is, ffp->start_time != AV_NOPTS_VALUE ? ffp->start_time : 0, 0, 0);
            } else if (ffp->autoexit) {
                ret = AVERROR_EOF;
                goto fail;
            } else {
2758
                ffp_statistic_l(ffp);
2759
                if (completed) {
2760
                    av_log(ffp, AV_LOG_INFO, "ffp_toggle_buffering: eof\n");
2761 2762
                    SDL_LockMutex(wait_mutex);
                    // infinite wait may block shutdown
B
bbcallen 已提交
2763
                    while(!is->abort_request && !is->seek_req)
Z
Zhang Rui 已提交
2764
                        SDL_CondWaitTimeout(is->continue_read_thread, wait_mutex, 100);
2765
                    SDL_UnlockMutex(wait_mutex);
B
bbcallen 已提交
2766 2767
                    if (!is->abort_request)
                        continue;
2768 2769
                } else {
                    completed = 1;
Z
Zhang Rui 已提交
2770
                    ffp->auto_resume = 0;
2771 2772 2773 2774

                    // TODO: 0 it's a bit early to notify complete here
                    ffp_toggle_buffering(ffp, 0);
                    toggle_pause(ffp, 1);
Z
Zhang Rui 已提交
2775
                    if (ffp->error) {
2776
                        av_log(ffp, AV_LOG_INFO, "ffp_toggle_buffering: error: %d\n", ffp->error);
Z
Zhang Rui 已提交
2777 2778
                        ffp_notify_msg1(ffp, FFP_MSG_ERROR);
                    } else {
2779
                        av_log(ffp, AV_LOG_INFO, "ffp_toggle_buffering: completed: OK\n");
Z
Zhang Rui 已提交
2780 2781
                        ffp_notify_msg1(ffp, FFP_MSG_COMPLETED);
                    }
2782 2783 2784
                }
            }
        }
2785
        pkt->flags = 0;
2786 2787
        ret = av_read_frame(ic, pkt);
        if (ret < 0) {
Z
Zhang Rui 已提交
2788 2789
            int pb_eof = 0;
            int pb_error = 0;
2790
            if ((ret == AVERROR_EOF || avio_feof(ic->pb)) && !is->eof) {
Z
Zhang Rui 已提交
2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803
                pb_eof = 1;
                // check error later
            }
            if (ic->pb && ic->pb->error) {
                pb_eof = 1;
                pb_error = ic->pb->error;
            }
            if (ret == AVERROR_EXIT) {
                pb_eof = 1;
                pb_error = AVERROR_EXIT;
            }

            if (pb_eof) {
2804 2805 2806 2807 2808 2809 2810 2811
                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);
#ifdef FFP_MERGE
                if (is->subtitle_stream >= 0)
                    packet_queue_put_nullpacket(&is->subtitleq, is->subtitle_stream);
#endif
2812
                is->eof = 1;
2813
            }
Z
Zhang Rui 已提交
2814
            if (pb_error) {
2815 2816 2817 2818 2819 2820 2821 2822
                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);
#ifdef FFP_MERGE
                if (is->subtitle_stream >= 0)
                    packet_queue_put_nullpacket(&is->subtitleq, is->subtitle_stream);
#endif
2823
                is->eof = 1;
Z
Zhang Rui 已提交
2824
                ffp->error = pb_error;
2825
                av_log(ffp, AV_LOG_ERROR, "av_read_frame error: %x(%c,%c,%c,%c): %s\n", ffp->error,
Z
Zhang Rui 已提交
2826 2827 2828
                      (char) (0xff & (ffp->error >> 24)),
                      (char) (0xff & (ffp->error >> 16)),
                      (char) (0xff & (ffp->error >> 8)),
Z
Zhang Rui 已提交
2829 2830
                      (char) (0xff & (ffp->error)),
                      ffp_get_error_string(ffp->error));
Z
Zhang Rui 已提交
2831
                // break;
Z
Zhang Rui 已提交
2832 2833
            } else {
                ffp->error = 0;
Z
Zhang Rui 已提交
2834
            }
2835
            if (is->eof) {
2836 2837 2838
                ffp_toggle_buffering(ffp, 0);
                SDL_Delay(1000);
            }
2839 2840 2841
            SDL_LockMutex(wait_mutex);
            SDL_CondWaitTimeout(is->continue_read_thread, wait_mutex, 10);
            SDL_UnlockMutex(wait_mutex);
2842
            ffp_statistic_l(ffp);
2843
            continue;
2844
        } else {
2845
            is->eof = 0;
2846
        }
Z
Zhang Rui 已提交
2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861

        if (pkt->flags & AV_PKT_FLAG_DISCONTINUITY) {
            if (is->audio_stream >= 0) {
                packet_queue_put(&is->audioq, &flush_pkt);
            }
#ifdef FFP_MERGE
            if (is->subtitle_stream >= 0) {
                packet_queue_put(&is->subtitleq, &flush_pkt);
            }
#endif
            if (is->video_stream >= 0) {
                packet_queue_put(&is->videoq, &flush_pkt);
            }
        }

2862
        /* check if packet is in play range specified by user, then queue, otherwise discard */
Z
Zhang Rui 已提交
2863
        stream_start_time = ic->streams[pkt->stream_index]->start_time;
2864
        pkt_ts = pkt->pts == AV_NOPTS_VALUE ? pkt->dts : pkt->pts;
2865
        pkt_in_play_range = ffp->duration == AV_NOPTS_VALUE ||
2866
                (pkt_ts - (stream_start_time != AV_NOPTS_VALUE ? stream_start_time : 0)) *
Z
Zhang Rui 已提交
2867
                av_q2d(ic->streams[pkt->stream_index]->time_base) -
Z
Zhang Rui 已提交
2868 2869
                (double)(ffp->start_time != AV_NOPTS_VALUE ? ffp->start_time : 0) / 1000000
                <= ((double)ffp->duration / 1000000);
2870 2871
        if (pkt->stream_index == is->audio_stream && pkt_in_play_range) {
            packet_queue_put(&is->audioq, pkt);
Z
Zhang Rui 已提交
2872
        } else if (pkt->stream_index == is->video_stream && pkt_in_play_range
Z
Zhang Rui 已提交
2873
                   && !(is->video_st && (is->video_st->disposition & AV_DISPOSITION_ATTACHED_PIC))) {
2874
            packet_queue_put(&is->videoq, pkt);
Z
Zhang Rui 已提交
2875
#ifdef FFP_MERGE
2876 2877
        } else if (pkt->stream_index == is->subtitle_stream && pkt_in_play_range) {
            packet_queue_put(&is->subtitleq, pkt);
Z
Zhang Rui 已提交
2878
#endif
2879 2880 2881
        } else {
            av_free_packet(pkt);
        }
Z
Zhang Rui 已提交
2882

2883
        ffp_statistic_l(ffp);
2884

2885 2886 2887 2888 2889 2890
        if (ffp->packet_buffering) {
            io_tick_counter = SDL_GetTickHR();
            if (abs((int)(io_tick_counter - prev_io_tick_counter)) > BUFFERING_CHECK_PER_MILLISECONDS) {
                prev_io_tick_counter = io_tick_counter;
                ffp_check_buffering_l(ffp);
            }
2891
        }
2892 2893 2894
    }

    ret = 0;
Z
Zhang Rui 已提交
2895
 fail:
2896
    if (ic && !is->ic)
Z
Zhang Rui 已提交
2897
        avformat_close_input(&ic);
2898

Z
Zhang Rui 已提交
2899
    if (!ffp->prepared || !is->abort_request) {
2900
        ffp->last_error = last_error;
2901
        ffp_notify_msg2(ffp, FFP_MSG_ERROR, last_error);
2902 2903 2904 2905 2906
    }
    SDL_DestroyMutex(wait_mutex);
    return 0;
}

2907
static int video_refresh_thread(void *arg);
2908 2909
static VideoState *stream_open(FFPlayer *ffp, const char *filename, AVInputFormat *iformat)
{
2910
    assert(!ffp->is);
Z
Zhang Rui 已提交
2911 2912 2913
    VideoState *is;

    is = av_mallocz(sizeof(VideoState));
2914 2915
    if (!is)
        return NULL;
2916 2917 2918
    is->filename = av_strdup(filename);
    if (!is->filename)
        goto fail;
2919
    is->iformat = iformat;
Z
Zhang Rui 已提交
2920 2921
    is->ytop    = 0;
    is->xleft   = 0;
2922 2923

    /* start video display */
2924
    if (frame_queue_init(&is->pictq, &is->videoq, ffp->pictq_size, 1) < 0)
2925
        goto fail;
Z
Zhang Rui 已提交
2926
#ifdef FFP_MERGE
2927 2928
    if (frame_queue_init(&is->subpq, &is->subtitleq, SUBPICTURE_QUEUE_SIZE, 0) < 0)
        goto fail;
Z
Zhang Rui 已提交
2929
#endif
2930 2931
    if (frame_queue_init(&is->sampq, &is->audioq, SAMPLE_QUEUE_SIZE, 1) < 0)
        goto fail;
2932

2933 2934
    if (packet_queue_init(&is->videoq) < 0 ||
        packet_queue_init(&is->audioq) < 0 ||
Z
Zhang Rui 已提交
2935
#ifdef FFP_MERGE
2936 2937 2938
        packet_queue_init(&is->subtitleq) < 0)
#else
        0)
Z
Zhang Rui 已提交
2939
#endif
2940
        goto fail;
2941

2942 2943 2944 2945
    if (!(is->continue_read_thread = SDL_CreateCond())) {
        av_log(NULL, AV_LOG_FATAL, "SDL_CreateCond(): %s\n", SDL_GetError());
        goto fail;
    }
2946

Z
Zhang Rui 已提交
2947 2948 2949
    init_clock(&is->vidclk, &is->videoq.serial);
    init_clock(&is->audclk, &is->audioq.serial);
    init_clock(&is->extclk, &is->extclk.serial);
2950
    is->audio_clock_serial = -1;
2951 2952
    is->audio_volume = SDL_MIX_MAXVOLUME;
    is->muted = 0;
2953
    is->av_sync_type = ffp->av_sync_type;
2954

2955
    is->play_mutex = SDL_CreateMutex();
2956
    ffp->is = is;
2957
    is->pause_req = !ffp->start_on_prepared;
2958

Z
Zhang Rui 已提交
2959
    is->video_refresh_tid = SDL_CreateThreadEx(&is->_video_refresh_tid, video_refresh_thread, ffp, "ff_vout");
2960
    if (!is->video_refresh_tid) {
2961
        av_freep(&ffp->is);
2962 2963 2964
        return NULL;
    }

Z
Zhang Rui 已提交
2965
    is->read_tid = SDL_CreateThreadEx(&is->_read_tid, read_thread, ffp, "ff_read");
2966
    if (!is->read_tid) {
2967
        av_log(NULL, AV_LOG_FATAL, "SDL_CreateThread(): %s\n", SDL_GetError());
2968
fail:
2969
        is->abort_request = true;
2970 2971
        if (is->video_refresh_tid)
            SDL_WaitThread(is->video_refresh_tid, NULL);
2972
        stream_close(ffp);
2973 2974 2975 2976
        return NULL;
    }
    return is;
}
2977

Z
Zhang Rui 已提交
2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997
// FFP_MERGE: stream_cycle_channel
// FFP_MERGE: toggle_full_screen
// FFP_MERGE: toggle_audio_display
// FFP_MERGE: refresh_loop_wait_event
// FFP_MERGE: event_loop
// FFP_MERGE: opt_frame_size
// FFP_MERGE: opt_width
// FFP_MERGE: opt_height
// FFP_MERGE: opt_format
// FFP_MERGE: opt_frame_pix_fmt
// FFP_MERGE: opt_sync
// FFP_MERGE: opt_seek
// FFP_MERGE: opt_duration
// FFP_MERGE: opt_show_mode
// FFP_MERGE: opt_input_file
// FFP_MERGE: opt_codec
// FFP_MERGE: dummy
// FFP_MERGE: options
// FFP_MERGE: show_usage
// FFP_MERGE: show_help_default
Z
Zhang Rui 已提交
2998
static int video_refresh_thread(void *arg)
2999 3000
{
    FFPlayer *ffp = arg;
3001
    VideoState *is = ffp->is;
3002
    double remaining_time = 0.0;
3003
    while (!is->abort_request) {
3004
        if (remaining_time > 0.0)
B
bbcallen 已提交
3005
            av_usleep((int)(int64_t)(remaining_time * 1000000.0));
3006 3007
        remaining_time = REFRESH_RATE;
        if (is->show_mode != SHOW_MODE_NONE && (!is->paused || is->force_refresh))
Z
Zhang Rui 已提交
3008
            video_refresh(ffp, &remaining_time);
3009
    }
3010 3011

    return 0;
3012
}
3013

3014 3015
static int lockmgr(void **mtx, enum AVLockOp op)
{
Z
Zhang Rui 已提交
3016 3017 3018
    switch (op) {
    case AV_LOCK_CREATE:
        *mtx = SDL_CreateMutex();
3019 3020
        if (!*mtx) {
            av_log(NULL, AV_LOG_FATAL, "SDL_CreateMutex(): %s\n", SDL_GetError());
Z
Zhang Rui 已提交
3021
            return 1;
3022
        }
Z
Zhang Rui 已提交
3023 3024 3025 3026 3027 3028 3029 3030 3031 3032
        return 0;
    case AV_LOCK_OBTAIN:
        return !!SDL_LockMutex(*mtx);
    case AV_LOCK_RELEASE:
        return !!SDL_UnlockMutex(*mtx);
    case AV_LOCK_DESTROY:
        SDL_DestroyMutex(*mtx);
        return 0;
    }
    return 1;
3033 3034
}

Z
Zhang Rui 已提交
3035
// FFP_MERGE: main
3036 3037 3038 3039 3040 3041

/*****************************************************************************
 * end last line in ffplay.c
 ****************************************************************************/

static bool g_ffmpeg_global_inited = false;
Z
Zhang Rui 已提交
3042

3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073
inline static int log_level_av_to_ijk(int av_level)
{
    int ijk_level = IJK_LOG_VERBOSE;
    if      (av_level <= AV_LOG_PANIC)      ijk_level = IJK_LOG_FATAL;
    else if (av_level <= AV_LOG_FATAL)      ijk_level = IJK_LOG_FATAL;
    else if (av_level <= AV_LOG_ERROR)      ijk_level = IJK_LOG_ERROR;
    else if (av_level <= AV_LOG_WARNING)    ijk_level = IJK_LOG_WARN;
    else if (av_level <= AV_LOG_INFO)       ijk_level = IJK_LOG_INFO;
    // AV_LOG_VERBOSE means detailed info
    else if (av_level <= AV_LOG_VERBOSE)    ijk_level = IJK_LOG_INFO;
    else if (av_level <= AV_LOG_DEBUG)      ijk_level = IJK_LOG_DEBUG;
    else if (av_level <= AV_LOG_TRACE)      ijk_level = IJK_LOG_VERBOSE;
    else                                    ijk_level = IJK_LOG_VERBOSE;
    return ijk_level;
}

inline static int log_level_ijk_to_av(int ijk_level)
{
    int av_level = IJK_LOG_VERBOSE;
    if      (ijk_level >= IJK_LOG_SILENT)   av_level = AV_LOG_QUIET;
    else if (ijk_level >= IJK_LOG_FATAL)    av_level = AV_LOG_FATAL;
    else if (ijk_level >= IJK_LOG_ERROR)    av_level = AV_LOG_ERROR;
    else if (ijk_level >= IJK_LOG_WARN)     av_level = AV_LOG_WARNING;
    else if (ijk_level >= IJK_LOG_INFO)     av_level = AV_LOG_INFO;
    // AV_LOG_VERBOSE means detailed info
    else if (ijk_level >= IJK_LOG_DEBUG)    av_level = AV_LOG_DEBUG;
    else if (ijk_level >= IJK_LOG_VERBOSE)  av_level = AV_LOG_TRACE;
    else if (ijk_level >= IJK_LOG_DEFAULT)  av_level = AV_LOG_TRACE;
    else if (ijk_level >= IJK_LOG_UNKNOWN)  av_level = AV_LOG_TRACE;
    else                                    av_level = AV_LOG_TRACE;
    return av_level;
Z
Zhang Rui 已提交
3074
}
3075

3076
static void ffp_log_callback_brief(void *ptr, int level, const char *fmt, va_list vl)
3077
{
Z
Zhang Rui 已提交
3078 3079
    if (level > av_log_get_level())
        return;
3080

3081
    int ffplv __unused = log_level_av_to_ijk(level);
Z
Zhang Rui 已提交
3082
    VLOG(ffplv, IJK_LOG_TAG, fmt, vl);
3083 3084
}

3085 3086
static void ffp_log_callback_report(void *ptr, int level, const char *fmt, va_list vl)
{
Z
Zhang Rui 已提交
3087 3088
    if (level > av_log_get_level())
        return;
Z
Zhang Rui 已提交
3089

3090
    int ffplv __unused = log_level_av_to_ijk(level);
Z
Zhang Rui 已提交
3091

3092 3093 3094 3095 3096
    va_list vl2;
    char line[1024];
    static int print_prefix = 1;

    va_copy(vl2, vl);
Z
Zhang Rui 已提交
3097
    // av_log_default_callback(ptr, level, fmt, vl);
3098 3099 3100 3101 3102 3103
    av_log_format_line(ptr, level, fmt, vl2, line, sizeof(line), &print_prefix);
    va_end(vl2);

    ALOG(ffplv, IJK_LOG_TAG, "%s", line);
}

Z
Zhang Rui 已提交
3104
void ffp_global_init()
3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117
{
    if (g_ffmpeg_global_inited)
        return;

    /* register all codecs, demux and protocols */
    avcodec_register_all();
#if CONFIG_AVDEVICE
    avdevice_register_all();
#endif
#if CONFIG_AVFILTER
    avfilter_register_all();
#endif
    av_register_all();
Z
Zhang Rui 已提交
3118 3119 3120

    ijkav_register_all();

3121 3122 3123
    avformat_network_init();

    av_lockmgr_register(lockmgr);
Z
Zhang Rui 已提交
3124
    av_log_set_callback(ffp_log_callback_brief);
3125 3126

    av_init_packet(&flush_pkt);
Z
Zhang Rui 已提交
3127
    flush_pkt.data = (uint8_t *)&flush_pkt;
3128 3129 3130 3131

    g_ffmpeg_global_inited = true;
}

Z
Zhang Rui 已提交
3132
void ffp_global_uninit()
3133 3134 3135 3136 3137 3138
{
    if (!g_ffmpeg_global_inited)
        return;

    av_lockmgr_register(NULL);

Z
Zhang Rui 已提交
3139 3140
    // FFP_MERGE: uninit_opts

3141 3142 3143 3144
    avformat_network_deinit();

    g_ffmpeg_global_inited = false;
}
Z
Zhang Rui 已提交
3145

3146
void ffp_global_set_log_report(int use_report)
3147 3148 3149 3150 3151 3152 3153 3154
{
    if (use_report) {
        av_log_set_callback(ffp_log_callback_report);
    } else {
        av_log_set_callback(ffp_log_callback_brief);
    }
}

3155
void ffp_global_set_log_level(int log_level)
Z
Zhang Rui 已提交
3156
{
3157 3158
    int av_level = log_level_ijk_to_av(log_level);
    av_log_set_level(av_level);
Z
Zhang Rui 已提交
3159 3160
}

Z
Zhang Rui 已提交
3161 3162 3163 3164 3165
void ffp_global_set_inject_callback(ijk_inject_callback cb)
{
    ijkav_register_inject_callback(cb);
}

3166 3167
void ffp_io_stat_register(void (*cb)(const char *url, int type, int bytes))
{
Z
Zhang Rui 已提交
3168
    // avijk_io_stat_register(cb);
3169
}
Z
Zhang Rui 已提交
3170

Z
Zhang Rui 已提交
3171 3172 3173
void ffp_io_stat_complete_register(void (*cb)(const char *url,
                                              int64_t read_bytes, int64_t total_size,
                                              int64_t elpased_time, int64_t total_duration))
Z
Zhang Rui 已提交
3174
{
Z
Zhang Rui 已提交
3175
    // avijk_io_stat_complete_register(cb);
Z
Zhang Rui 已提交
3176 3177
}

3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202
static const char *ffp_context_to_name(void *ptr)
{
    return "FFPlayer";
}


static void *ffp_context_child_next(void *obj, void *prev)
{
    return NULL;
}

static const AVClass *ffp_context_child_class_next(const AVClass *prev)
{
    return NULL;
}

const AVClass ffp_context_class = {
    .class_name       = "FFPlayer",
    .item_name        = ffp_context_to_name,
    .option           = ffp_context_options,
    .version          = LIBAVUTIL_VERSION_INT,
    .child_next       = ffp_context_child_next,
    .child_class_next = ffp_context_child_class_next,
};

Z
Zhang Rui 已提交
3203
FFPlayer *ffp_create()
Z
Zhang Rui 已提交
3204
{
Z
Zhang Rui 已提交
3205 3206
    av_log(NULL, AV_LOG_INFO, "av_version_info: %s\n", av_version_info());

Z
Zhang Rui 已提交
3207
    FFPlayer* ffp = (FFPlayer*) av_mallocz(sizeof(FFPlayer));
Z
Zhang Rui 已提交
3208 3209 3210
    if (!ffp)
        return NULL;

Z
Zhang Rui 已提交
3211
    msg_queue_init(&ffp->msg_queue);
Z
Zhang Rui 已提交
3212 3213 3214
    ffp->af_mutex = SDL_CreateMutex();
    ffp->vf_mutex = SDL_CreateMutex();

Z
Zhang Rui 已提交
3215
    ffp_reset_internal(ffp);
3216
    ffp->av_class = &ffp_context_class;
Z
Zhang Rui 已提交
3217
    ffp->meta = ijkmeta_create();
3218 3219 3220

    av_opt_set_defaults(ffp);

Z
Zhang Rui 已提交
3221 3222 3223
    return ffp;
}

Z
Zhang Rui 已提交
3224
void ffp_destroy(FFPlayer *ffp)
Z
Zhang Rui 已提交
3225
{
Z
Zhang Rui 已提交
3226
    if (!ffp)
Z
Zhang Rui 已提交
3227 3228
        return;

3229
    if (ffp->is) {
Z
Zhang Rui 已提交
3230
        av_log(NULL, AV_LOG_WARNING, "ffp_destroy_ffplayer: force stream_close()");
3231
        stream_close(ffp);
3232 3233 3234
        ffp->is = NULL;
    }

Z
Zhang Rui 已提交
3235 3236
    SDL_VoutFreeP(&ffp->vout);
    SDL_AoutFreeP(&ffp->aout);
3237
    ffpipenode_free_p(&ffp->node_vdec);
Z
Zhang Rui 已提交
3238
    ffpipeline_free_p(&ffp->pipeline);
3239
    ijkmeta_destroy_p(&ffp->meta);
Z
Zhang Rui 已提交
3240
    ffp_reset_internal(ffp);
Z
Zhang Rui 已提交
3241

Z
Zhang Rui 已提交
3242 3243 3244
    SDL_DestroyMutexP(&ffp->af_mutex);
    SDL_DestroyMutexP(&ffp->vf_mutex);

Z
Zhang Rui 已提交
3245
    msg_queue_destroy(&ffp->msg_queue);
Z
Zhang Rui 已提交
3246

Z
Zhang Rui 已提交
3247

Z
Zhang Rui 已提交
3248
    av_free(ffp);
Z
Zhang Rui 已提交
3249 3250
}

Z
Zhang Rui 已提交
3251
void ffp_destroy_p(FFPlayer **pffp)
Z
Zhang Rui 已提交
3252
{
Z
Zhang Rui 已提交
3253 3254 3255 3256 3257
    if (!pffp)
        return;

    ffp_destroy(*pffp);
    *pffp = NULL;
Z
Zhang Rui 已提交
3258 3259
}

3260 3261 3262 3263 3264 3265 3266
static AVDictionary **ffp_get_opt_dict(FFPlayer *ffp, int opt_category)
{
    assert(ffp);

    switch (opt_category) {
        case FFP_OPT_CATEGORY_FORMAT:   return &ffp->format_opts;
        case FFP_OPT_CATEGORY_CODEC:    return &ffp->codec_opts;
Z
Zhang Rui 已提交
3267
        case FFP_OPT_CATEGORY_SWS:      return &ffp->sws_dict;
3268
        case FFP_OPT_CATEGORY_PLAYER:   return &ffp->player_opts;
Z
Zhang Rui 已提交
3269
        case FFP_OPT_CATEGORY_SWR:      return &ffp->swr_opts;
3270
        default:
3271
            av_log(ffp, AV_LOG_ERROR, "unknown option category %d\n", opt_category);
3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293
            return NULL;
    }
}

void ffp_set_option(FFPlayer *ffp, int opt_category, const char *name, const char *value)
{
    if (!ffp)
        return;

    AVDictionary **dict = ffp_get_opt_dict(ffp, opt_category);
    av_dict_set(dict, name, value, 0);
}

void ffp_set_option_int(FFPlayer *ffp, int opt_category, const char *name, int64_t value)
{
    if (!ffp)
        return;

    AVDictionary **dict = ffp_get_opt_dict(ffp, opt_category);
    av_dict_set_int(dict, name, value, 0);
}

Z
Zhang Rui 已提交
3294 3295 3296
void ffp_set_overlay_format(FFPlayer *ffp, int chroma_fourcc)
{
    switch (chroma_fourcc) {
3297
        case SDL_FCC__GLES2:
Z
Zhang Rui 已提交
3298
        case SDL_FCC_I420:
Z
Zhang Rui 已提交
3299 3300
        case SDL_FCC_YV12:
        case SDL_FCC_RV16:
3301
        case SDL_FCC_RV24:
Z
Zhang Rui 已提交
3302 3303 3304
        case SDL_FCC_RV32:
            ffp->overlay_format = chroma_fourcc;
            break;
Z
Zhang Rui 已提交
3305 3306 3307 3308 3309
#ifdef __APPLE__
        case SDL_FCC_I444P10LE:
            ffp->overlay_format = chroma_fourcc;
            break;
#endif
Z
Zhang Rui 已提交
3310
        default:
3311
            av_log(ffp, AV_LOG_ERROR, "ffp_set_overlay_format: unknown chroma fourcc: %d\n", chroma_fourcc);
Z
Zhang Rui 已提交
3312 3313 3314 3315
            break;
    }
}

Z
Zhang Rui 已提交
3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343
int ffp_get_video_codec_info(FFPlayer *ffp, char **codec_info)
{
    if (!codec_info)
        return -1;

    // FIXME: not thread-safe
    if (ffp->video_codec_info) {
        *codec_info = strdup(ffp->video_codec_info);
    } else {
        *codec_info = NULL;
    }
    return 0;
}

int ffp_get_audio_codec_info(FFPlayer *ffp, char **codec_info)
{
    if (!codec_info)
        return -1;

    // FIXME: not thread-safe
    if (ffp->audio_codec_info) {
        *codec_info = strdup(ffp->audio_codec_info);
    } else {
        *codec_info = NULL;
    }
    return 0;
}

Z
Zhang Rui 已提交
3344
static void ffp_show_dict(FFPlayer *ffp, const char *tag, AVDictionary *dict)
3345 3346 3347 3348
{
    AVDictionaryEntry *t = NULL;

    while ((t = av_dict_get(dict, "", t, AV_DICT_IGNORE_SUFFIX))) {
Z
Zhang Rui 已提交
3349
        av_log(ffp, AV_LOG_INFO, "%-*s: %-*s = %s\n", 12, tag, 28, t->key, t->value);
3350 3351 3352
    }
}

Z
Zhang Rui 已提交
3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367
#define FFP_VERSION_MODULE_NAME_LENGTH 13
static void ffp_show_version_str(FFPlayer *ffp, const char *module, const char *version)
{
        av_log(ffp, AV_LOG_INFO, "%-*s: %s\n", FFP_VERSION_MODULE_NAME_LENGTH, module, version);
}

static void ffp_show_version_int(FFPlayer *ffp, const char *module, unsigned version)
{
    av_log(ffp, AV_LOG_INFO, "%-*s: %u.%u.%u\n",
           FFP_VERSION_MODULE_NAME_LENGTH, module,
           (unsigned int)IJKVERSION_GET_MAJOR(version),
           (unsigned int)IJKVERSION_GET_MINOR(version),
           (unsigned int)IJKVERSION_GET_MICRO(version));
}

Z
Zhang Rui 已提交
3368
int ffp_prepare_async_l(FFPlayer *ffp, const char *file_name)
Z
Zhang Rui 已提交
3369 3370
{
    assert(ffp);
3371
    assert(!ffp->is);
Z
Zhang Rui 已提交
3372 3373
    assert(file_name);

Z
Zhang Rui 已提交
3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389
    if (av_stristart(file_name, "rtmp", NULL) ||
        av_stristart(file_name, "rtsp", NULL)) {
        // There is total different meaning for 'timeout' option in rtmp
        av_log(ffp, AV_LOG_WARNING, "remove 'timeout' option for rtmp.\n");
        av_dict_set(&ffp->format_opts, "timeout", NULL, 0);
    }

    /* there is a length limit in avformat */
    if (strlen(file_name) + 1 > 1024) {
        av_log(ffp, AV_LOG_ERROR, "%s too long url\n", __func__);
        if (avio_find_protocol_name("ijklongurl:")) {
            av_dict_set(&ffp->format_opts, "ijklongurl-url", file_name, 0);
            file_name = "ijklongurl:";
        }
    }

Z
Zhang Rui 已提交
3390 3391 3392 3393 3394 3395 3396
    av_log(NULL, AV_LOG_INFO, "===== versions =====\n");
    ffp_show_version_str(ffp, "FFmpeg",         av_version_info());
    ffp_show_version_int(ffp, "libavutil",      avutil_version());
    ffp_show_version_int(ffp, "libavcodec",     avcodec_version());
    ffp_show_version_int(ffp, "libavformat",    avformat_version());
    ffp_show_version_int(ffp, "libswscale",     swscale_version());
    ffp_show_version_int(ffp, "libswresample",  swresample_version());
3397
    av_log(NULL, AV_LOG_INFO, "===== options =====\n");
Z
Zhang Rui 已提交
3398 3399 3400 3401 3402
    ffp_show_dict(ffp, "player-opts", ffp->player_opts);
    ffp_show_dict(ffp, "format-opts", ffp->format_opts);
    ffp_show_dict(ffp, "codec-opts ", ffp->codec_opts);
    ffp_show_dict(ffp, "sws-opts   ", ffp->sws_dict);
    ffp_show_dict(ffp, "swr-opts   ", ffp->swr_opts);
3403 3404
    av_log(NULL, AV_LOG_INFO, "===================\n");

3405
    av_opt_set_dict(ffp, &ffp->player_opts);
Z
Zhang Rui 已提交
3406 3407 3408 3409 3410
    if (!ffp->aout) {
        ffp->aout = ffpipeline_open_audio_output(ffp->pipeline, ffp);
        if (!ffp->aout)
            return -1;
    }
3411

Z
Zhang Rui 已提交
3412
#if CONFIG_AVFILTER
Z
Zhang Rui 已提交
3413 3414 3415 3416
    if (ffp->vfilter0) {
        GROW_ARRAY(ffp->vfilters_list, ffp->nb_vfilters);
        ffp->vfilters_list[ffp->nb_vfilters - 1] = ffp->vfilter0;
    }
Z
Zhang Rui 已提交
3417
#endif
Z
Zhang Rui 已提交
3418

Z
Zhang Rui 已提交
3419
    VideoState *is = stream_open(ffp, file_name, NULL);
3420
    if (!is) {
Z
Zhang Rui 已提交
3421
        av_log(NULL, AV_LOG_WARNING, "ffp_prepare_async_l: stream_open failed OOM");
Z
Zhang Rui 已提交
3422
        return EIJK_OUT_OF_MEMORY;
3423
    }
Z
Zhang Rui 已提交
3424

3425
    ffp->is = is;
3426
    ffp->input_filename = av_strdup(file_name);
Z
Zhang Rui 已提交
3427 3428 3429
    return 0;
}

Z
Zhang Rui 已提交
3430 3431 3432 3433 3434 3435 3436
int ffp_start_from_l(FFPlayer *ffp, long msec)
{
    assert(ffp);
    VideoState *is = ffp->is;
    if (!is)
        return EIJK_NULL_IS_PTR;

Z
Zhang Rui 已提交
3437
    ffp->auto_resume = 1;
Z
Zhang Rui 已提交
3438 3439 3440 3441 3442
    ffp_toggle_buffering(ffp, 1);
    ffp_seek_to_l(ffp, msec);
    return 0;
}

Z
Zhang Rui 已提交
3443
int ffp_start_l(FFPlayer *ffp)
Z
Zhang Rui 已提交
3444 3445
{
    assert(ffp);
3446 3447 3448 3449
    VideoState *is = ffp->is;
    if (!is)
        return EIJK_NULL_IS_PTR;

3450
    toggle_pause(ffp, 0);
Z
Zhang Rui 已提交
3451 3452 3453
    return 0;
}

Z
Zhang Rui 已提交
3454
int ffp_pause_l(FFPlayer *ffp)
Z
Zhang Rui 已提交
3455 3456
{
    assert(ffp);
3457 3458 3459 3460
    VideoState *is = ffp->is;
    if (!is)
        return EIJK_NULL_IS_PTR;

3461
    toggle_pause(ffp, 1);
Z
Zhang Rui 已提交
3462 3463
    return 0;
}
Z
Zhang Rui 已提交
3464

3465 3466 3467 3468 3469 3470 3471 3472 3473 3474
int ffp_is_paused_l(FFPlayer *ffp)
{
    assert(ffp);
    VideoState *is = ffp->is;
    if (!is)
        return 1;

    return is->paused;
}

Z
Zhang Rui 已提交
3475
int ffp_stop_l(FFPlayer *ffp)
Z
Zhang Rui 已提交
3476 3477
{
    assert(ffp);
3478
    VideoState *is = ffp->is;
Z
Zhang Rui 已提交
3479 3480 3481
    if (is)
        is->abort_request = 1;

3482
    msg_queue_abort(&ffp->msg_queue);
Z
Zhang Rui 已提交
3483 3484 3485
    return 0;
}

Z
Zhang Rui 已提交
3486
int ffp_wait_stop_l(FFPlayer *ffp)
Z
Zhang Rui 已提交
3487 3488
{
    assert(ffp);
3489

Z
Zhang Rui 已提交
3490 3491
    if (ffp->is) {
        ffp_stop_l(ffp);
3492
        stream_close(ffp);
Z
Zhang Rui 已提交
3493 3494
        ffp->is = NULL;
    }
Z
Zhang Rui 已提交
3495 3496
    return 0;
}
3497

Z
Zhang Rui 已提交
3498
int ffp_seek_to_l(FFPlayer *ffp, long msec)
Z
Zhang Rui 已提交
3499 3500 3501 3502 3503 3504
{
    assert(ffp);
    VideoState *is = ffp->is;
    if (!is)
        return EIJK_NULL_IS_PTR;

Z
Zhang Rui 已提交
3505 3506
    int64_t seek_pos = milliseconds_to_fftime(msec);
    int64_t start_time = is->ic->start_time;
3507
    if (start_time > 0 && start_time != AV_NOPTS_VALUE)
Z
Zhang Rui 已提交
3508 3509
        seek_pos += start_time;

Z
Zhang Rui 已提交
3510 3511 3512
    // FIXME: 9 seek by bytes
    // FIXME: 9 seek out of range
    // FIXME: 9 seekable
3513
    av_log(ffp, AV_LOG_DEBUG, "stream_seek %"PRId64"(%d) + %"PRId64", \n", seek_pos, (int)msec, start_time);
Z
Zhang Rui 已提交
3514
    stream_seek(is, seek_pos, 0, 0);
Z
Zhang Rui 已提交
3515 3516 3517
    return 0;
}

Z
Zhang Rui 已提交
3518
long ffp_get_current_position_l(FFPlayer *ffp)
3519 3520 3521 3522 3523 3524
{
    assert(ffp);
    VideoState *is = ffp->is;
    if (!is || !is->ic)
        return 0;

3525 3526 3527
    int64_t start_time = is->ic->start_time;
    int64_t start_diff = 0;
    if (start_time > 0 && start_time != AV_NOPTS_VALUE)
Z
Zhang Rui 已提交
3528
        start_diff = fftime_to_milliseconds(start_time);
3529 3530

    int64_t pos = 0;
Z
Zhang Rui 已提交
3531 3532
    double pos_clock = get_master_clock(is);
    if (isnan(pos_clock)) {
3533
        pos = fftime_to_milliseconds(is->seek_pos);
3534 3535 3536
    } else {
        pos = pos_clock * 1000;
    }
3537

S
seans 已提交
3538 3539 3540 3541 3542
    // If using REAL time and not ajusted, then return the real pos as calculated from the stream
    // the use case for this is primarily when using a custom non-seekable data source that starts
    // with a buffer that is NOT the start of the stream.  We want the get_current_position to
    // return the time in the stream, and not the player's internal clock.
    if (ffp->no_time_adjust) {
Z
Zhang Rui 已提交
3543
        return (long)pos;
S
seans 已提交
3544 3545
    }

3546
    if (pos < 0 || pos < start_diff)
3547 3548
        return 0;

3549
    int64_t adjust_pos = pos - start_diff;
3550
    return (long)adjust_pos;
3551 3552
}

Z
Zhang Rui 已提交
3553
long ffp_get_duration_l(FFPlayer *ffp)
3554 3555 3556 3557 3558 3559
{
    assert(ffp);
    VideoState *is = ffp->is;
    if (!is || !is->ic)
        return 0;

3560
    int64_t duration = fftime_to_milliseconds(is->ic->duration);
3561
    if (duration < 0)
3562 3563
        return 0;

3564
    return (long)duration;
3565
}
3566

3567 3568 3569 3570 3571 3572 3573 3574 3575
long ffp_get_playable_duration_l(FFPlayer *ffp)
{
    assert(ffp);
    if (!ffp)
        return 0;

    return (long)ffp->playable_duration_ms;
}

Z
Zhang Rui 已提交
3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591
void ffp_set_loop(FFPlayer *ffp, int loop)
{
    assert(ffp);
    if (!ffp)
        return;
    ffp->loop = loop;
}

int ffp_get_loop(FFPlayer *ffp)
{
    assert(ffp);
    if (!ffp)
        return 1;
    return ffp->loop;
}

3592
int ffp_packet_queue_init(PacketQueue *q)
Z
Zhang Rui 已提交
3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649
{
    return packet_queue_init(q);
}

void ffp_packet_queue_destroy(PacketQueue *q)
{
    return packet_queue_destroy(q);
}

void ffp_packet_queue_abort(PacketQueue *q)
{
    return packet_queue_abort(q);
}

void ffp_packet_queue_start(PacketQueue *q)
{
    return packet_queue_start(q);
}

void ffp_packet_queue_flush(PacketQueue *q)
{
    return packet_queue_flush(q);
}

int ffp_packet_queue_get(PacketQueue *q, AVPacket *pkt, int block, int *serial)
{
    return packet_queue_get(q, pkt, block, serial);
}

int ffp_packet_queue_get_or_buffering(FFPlayer *ffp, PacketQueue *q, AVPacket *pkt, int *serial, int *finished)
{
    return packet_queue_get_or_buffering(ffp, q, pkt, serial, finished);
}

int ffp_packet_queue_put(PacketQueue *q, AVPacket *pkt)
{
    return packet_queue_put(q, pkt);
}

bool ffp_is_flush_packet(AVPacket *pkt)
{
    if (!pkt)
        return false;

    return pkt->data == flush_pkt.data;
}

Frame *ffp_frame_queue_peek_writable(FrameQueue *f)
{
    return frame_queue_peek_writable(f);
}

void ffp_frame_queue_push(FrameQueue *f)
{
    return frame_queue_push(f);
}

3650 3651 3652 3653 3654
int ffp_queue_picture(FFPlayer *ffp, AVFrame *src_frame, double pts, double duration, int64_t pos, int serial)
{
    return queue_picture(ffp, src_frame, pts, duration, pos, serial);
}

3655 3656 3657 3658 3659 3660 3661 3662 3663 3664
int ffp_get_master_sync_type(VideoState *is)
{
    return get_master_sync_type(is);
}

double ffp_get_master_clock(VideoState *is)
{
    return get_master_clock(is);
}

3665
void ffp_toggle_buffering_l(FFPlayer *ffp, int buffering_on)
3666
{
3667 3668 3669
    if (!ffp->packet_buffering)
        return;

3670
    VideoState *is = ffp->is;
3671
    if (buffering_on && !is->buffering_on) {
3672
        av_log(ffp, AV_LOG_DEBUG, "ffp_toggle_buffering_l: start\n");
3673 3674
        is->buffering_on = 1;
        stream_update_pause_l(ffp);
3675
        ffp_notify_msg1(ffp, FFP_MSG_BUFFERING_START);
3676
    } else if (!buffering_on && is->buffering_on){
3677
        av_log(ffp, AV_LOG_DEBUG, "ffp_toggle_buffering_l: end\n");
3678 3679
        is->buffering_on = 0;
        stream_update_pause_l(ffp);
3680
        ffp_notify_msg1(ffp, FFP_MSG_BUFFERING_END);
3681 3682 3683 3684 3685 3686 3687 3688 3689
    }
}

void ffp_toggle_buffering(FFPlayer *ffp, int start_buffering)
{
    SDL_LockMutex(ffp->is->play_mutex);
    ffp_toggle_buffering_l(ffp, start_buffering);
    SDL_UnlockMutex(ffp->is->play_mutex);
}
3690

Z
Zhang Rui 已提交
3691
void ffp_track_statistic_l(FFPlayer *ffp, AVStream *st, PacketQueue *q, FFTrackCacheStatistic *cache)
3692
{
Z
Zhang Rui 已提交
3693
    assert(cache);
3694

Z
Zhang Rui 已提交
3695 3696 3697
    if (q) {
        cache->bytes   = q->size;
        cache->packets = q->nb_packets;
3698
    }
Z
Zhang Rui 已提交
3699 3700 3701

    if (st && st->time_base.den > 0 && st->time_base.num > 0) {
        cache->duration = q->duration * av_q2d(st->time_base) * 1000;
3702 3703 3704
    }
}

3705
void ffp_audio_statistic_l(FFPlayer *ffp)
Z
Zhang Rui 已提交
3706 3707
{
    VideoState *is = ffp->is;
3708 3709
    ffp_track_statistic_l(ffp, is->audio_st, &is->audioq, &ffp->stat.audio_cache);
}
Z
Zhang Rui 已提交
3710

3711 3712 3713
void ffp_video_statistic_l(FFPlayer *ffp)
{
    VideoState *is = ffp->is;
Z
Zhang Rui 已提交
3714
    ffp_track_statistic_l(ffp, is->video_st, &is->videoq, &ffp->stat.video_cache);
3715 3716 3717 3718 3719 3720
}

void ffp_statistic_l(FFPlayer *ffp)
{
    ffp_audio_statistic_l(ffp);
    ffp_video_statistic_l(ffp);
Z
Zhang Rui 已提交
3721 3722
}

3723 3724 3725
void ffp_check_buffering_l(FFPlayer *ffp)
{
    VideoState *is            = ffp->is;
Z
Zhang Rui 已提交
3726
    int hwm_in_ms             = ffp->dcc.current_high_water_mark_in_ms; // use fast water mark for first loading
3727 3728
    int buf_size_percent      = -1;
    int buf_time_percent      = -1;
Z
Zhang Rui 已提交
3729
    int hwm_in_bytes          = ffp->dcc.high_water_mark_in_bytes;
3730
    int need_start_buffering  = 0;
3731 3732
    int audio_time_base_valid = 0;
    int video_time_base_valid = 0;
3733
    int64_t buf_time_position = -1;
3734 3735 3736 3737 3738 3739

    if(is->audio_st)
        audio_time_base_valid = is->audio_st->time_base.den > 0 && is->audio_st->time_base.num > 0;
    if(is->video_st)
        video_time_base_valid = is->video_st->time_base.den > 0 && is->video_st->time_base.num > 0;

3740 3741 3742 3743 3744 3745
    if (hwm_in_ms > 0) {
        int     cached_duration_in_ms = -1;
        int64_t audio_cached_duration = -1;
        int64_t video_cached_duration = -1;

        if (is->audio_st && audio_time_base_valid) {
Z
Zhang Rui 已提交
3746
            audio_cached_duration = ffp->stat.audio_cache.duration;
3747 3748
#ifdef FFP_SHOW_DEMUX_CACHE
            int audio_cached_percent = (int)av_rescale(audio_cached_duration, 1005, hwm_in_ms * 10);
Z
Zhang Rui 已提交
3749
            av_log(ffp, AV_LOG_DEBUG, "audio cache=%%%d milli:(%d/%d) bytes:(%d/%d) packet:(%d/%d)\n", audio_cached_percent,
Z
Zhang Rui 已提交
3750
                  (int)audio_cached_duration, hwm_in_ms,
Z
Zhang Rui 已提交
3751 3752
                  is->audioq.size, hwm_in_bytes,
                  is->audioq.nb_packets, MIN_FRAMES);
3753 3754 3755 3756
#endif
        }

        if (is->video_st && video_time_base_valid) {
Z
Zhang Rui 已提交
3757
            video_cached_duration = ffp->stat.video_cache.duration;
3758 3759
#ifdef FFP_SHOW_DEMUX_CACHE
            int video_cached_percent = (int)av_rescale(video_cached_duration, 1005, hwm_in_ms * 10);
Z
Zhang Rui 已提交
3760
            av_log(ffp, AV_LOG_DEBUG, "video cache=%%%d milli:(%d/%d) bytes:(%d/%d) packet:(%d/%d)\n", video_cached_percent,
Z
Zhang Rui 已提交
3761
                  (int)video_cached_duration, hwm_in_ms,
Z
Zhang Rui 已提交
3762 3763
                  is->videoq.size, hwm_in_bytes,
                  is->audioq.nb_packets, MIN_FRAMES);
3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776
#endif
        }

        if (video_cached_duration > 0 && audio_cached_duration > 0) {
            cached_duration_in_ms = (int)IJKMIN(video_cached_duration, audio_cached_duration);
        } else if (video_cached_duration > 0) {
            cached_duration_in_ms = (int)video_cached_duration;
        } else if (audio_cached_duration > 0) {
            cached_duration_in_ms = (int)audio_cached_duration;
        }

        if (cached_duration_in_ms >= 0) {
            buf_time_position = ffp_get_current_position_l(ffp) + cached_duration_in_ms;
3777 3778
            ffp->playable_duration_ms = buf_time_position;

3779 3780
            buf_time_percent = (int)av_rescale(cached_duration_in_ms, 1005, hwm_in_ms * 10);
#ifdef FFP_SHOW_DEMUX_CACHE
3781
            av_log(ffp, AV_LOG_DEBUG, "time cache=%%%d (%d/%d)\n", buf_time_percent, cached_duration_in_ms, hwm_in_ms);
3782 3783 3784
#endif
#ifdef FFP_NOTIFY_BUF_TIME
            ffp_notify_msg3(ffp, FFP_MSG_BUFFERING_TIME_UPDATE, cached_duration_in_ms, hwm_in_ms);
3785 3786 3787 3788 3789 3790 3791 3792
#endif
        }
    }

    int cached_size = is->audioq.size + is->videoq.size;
    if (hwm_in_bytes > 0) {
        buf_size_percent = (int)av_rescale(cached_size, 1005, hwm_in_bytes * 10);
#ifdef FFP_SHOW_DEMUX_CACHE
3793
        av_log(ffp, AV_LOG_DEBUG, "size cache=%%%d (%d/%d)\n", buf_size_percent, cached_size, hwm_in_bytes);
3794 3795 3796
#endif
#ifdef FFP_NOTIFY_BUF_BYTES
        ffp_notify_msg3(ffp, FFP_MSG_BUFFERING_BYTES_UPDATE, cached_size, hwm_in_bytes);
3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815
#endif
    }

    int buf_percent = -1;
    if (buf_time_percent >= 0) {
        // alwas depend on cache duration if valid
        if (buf_time_percent >= 100)
            need_start_buffering = 1;
        buf_percent = buf_time_percent;
    } else {
        if (buf_size_percent >= 100)
            need_start_buffering = 1;
        buf_percent = buf_size_percent;
    }

    if (buf_time_percent >= 0 && buf_size_percent >= 0) {
        buf_percent = FFMIN(buf_time_percent, buf_size_percent);
    }
    if (buf_percent) {
3816
#ifdef FFP_SHOW_BUF_POS
3817
        av_log(ffp, AV_LOG_DEBUG, "buf pos=%"PRId64", %%%d\n", buf_time_position, buf_percent);
3818
#endif
3819
        ffp_notify_msg3(ffp, FFP_MSG_BUFFERING_UPDATE, (int)buf_time_position, buf_percent);
3820 3821 3822
    }

    if (need_start_buffering) {
Z
Zhang Rui 已提交
3823 3824
        if (hwm_in_ms < ffp->dcc.next_high_water_mark_in_ms) {
            hwm_in_ms = ffp->dcc.next_high_water_mark_in_ms;
3825 3826 3827
        } else {
            hwm_in_ms *= 2;
        }
3828

Z
Zhang Rui 已提交
3829 3830
        if (hwm_in_ms > ffp->dcc.last_high_water_mark_in_ms)
            hwm_in_ms = ffp->dcc.last_high_water_mark_in_ms;
3831

Z
Zhang Rui 已提交
3832
        ffp->dcc.current_high_water_mark_in_ms = hwm_in_ms;
3833 3834

        if (is->buffer_indicator_queue && is->buffer_indicator_queue->nb_packets > 0) {
Z
Zhang Rui 已提交
3835 3836
            if (   (is->audioq.nb_packets > MIN_MIN_FRAMES || is->audio_stream < 0 || is->audioq.abort_request)
                && (is->videoq.nb_packets > MIN_MIN_FRAMES || is->video_stream < 0 || is->videoq.abort_request)) {
3837 3838
                ffp_toggle_buffering(ffp, 0);
            }
3839
        }
3840 3841
    }
}
3842

Z
Zhang Rui 已提交
3843 3844 3845 3846 3847
int ffp_video_thread(FFPlayer *ffp)
{
    return ffplay_video_thread(ffp);
}

Z
Zhang Rui 已提交
3848 3849 3850 3851
void ffp_set_video_codec_info(FFPlayer *ffp, const char *module, const char *codec)
{
    av_freep(&ffp->video_codec_info);
    ffp->video_codec_info = av_asprintf("%s, %s", module ? module : "", codec ? codec : "");
3852
    av_log(ffp, AV_LOG_INFO, "VideoCodec: %s\n", ffp->video_codec_info);
Z
Zhang Rui 已提交
3853 3854 3855 3856 3857 3858
}

void ffp_set_audio_codec_info(FFPlayer *ffp, const char *module, const char *codec)
{
    av_freep(&ffp->audio_codec_info);
    ffp->audio_codec_info = av_asprintf("%s, %s", module ? module : "", codec ? codec : "");
3859
    av_log(ffp, AV_LOG_INFO, "AudioCodec: %s\n", ffp->audio_codec_info);
Z
Zhang Rui 已提交
3860 3861
}

Z
Zhang Rui 已提交
3862 3863 3864 3865 3866 3867
void ffp_set_playback_rate(FFPlayer *ffp, float rate)
{
    if (!ffp)
        return;

    ffp->pf_playback_rate = rate;
Z
Zhang Rui 已提交
3868
    ffp->pf_playback_rate_changed = 1;
Z
Zhang Rui 已提交
3869 3870
}

Z
Zhang Rui 已提交
3871 3872 3873 3874 3875 3876
int ffp_get_video_rotate_degrees(FFPlayer *ffp)
{
    VideoState *is = ffp->is;
    if (!is)
        return 0;

Z
Zhang Rui 已提交
3877 3878 3879 3880 3881 3882 3883 3884
    int theta  = abs((int)((int64_t)round(fabs(get_rotation(is->video_st))) % 360));
    switch (theta) {
        case 0:
        case 90:
        case 180:
        case 270:
            break;
        case 360:
Z
Zhang Rui 已提交
3885
            theta = 0;
Z
Zhang Rui 已提交
3886 3887
            break;
        default:
Z
Zhang Rui 已提交
3888 3889
            ALOGW("Unknown rotate degress: %d\n", theta);
            theta = 0;
Z
Zhang Rui 已提交
3890
            break;
Z
Zhang Rui 已提交
3891 3892
    }

Z
Zhang Rui 已提交
3893
    return theta;
Z
Zhang Rui 已提交
3894 3895
}

3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946
int ffp_set_stream_selected(FFPlayer *ffp, int stream, int selected)
{
    VideoState      *is = ffp->is;
    AVFormatContext *ic = NULL;
    AVCodecContext  *avctx = NULL;
    if (!is)
        return -1;
    ic = is->ic;
    if (!ic)
        return -1;

    if (stream < 0 || stream >= ic->nb_streams) {
        av_log(ffp, AV_LOG_ERROR, "invalid stream index %d >= stream number (%d)\n", stream, ic->nb_streams);
        return -1;
    }

    avctx = ic->streams[stream]->codec;

    if (selected) {
        switch (avctx->codec_type) {
            case AVMEDIA_TYPE_VIDEO:
                if (stream != is->video_stream && is->video_stream >= 0)
                    stream_component_close(ffp, is->video_stream);
                break;
            case AVMEDIA_TYPE_AUDIO:
                if (stream != is->audio_stream && is->audio_stream >= 0)
                    stream_component_close(ffp, is->audio_stream);
                break;
            default:
                av_log(ffp, AV_LOG_ERROR, "select invalid stream %d of video type %d\n", stream, avctx->codec_type);
                return -1;
        }
        return stream_component_open(ffp, stream);
    } else {
        switch (avctx->codec_type) {
            case AVMEDIA_TYPE_VIDEO:
                if (stream == is->video_stream)
                    stream_component_close(ffp, is->video_stream);
                break;
            case AVMEDIA_TYPE_AUDIO:
                if (stream == is->audio_stream)
                    stream_component_close(ffp, is->audio_stream);
                break;
            default:
                av_log(ffp, AV_LOG_ERROR, "select invalid stream %d of audio type %d\n", stream, avctx->codec_type);
                return -1;
        }
        return 0;
    }
}

Z
Zhang Rui 已提交
3947
float ffp_get_property_float(FFPlayer *ffp, int id, float default_value)
Z
Zhang Rui 已提交
3948
{
Z
Zhang Rui 已提交
3949 3950
    switch (id) {
        case FFP_PROP_FLOAT_VIDEO_DECODE_FRAMES_PER_SECOND:
Z
Zhang Rui 已提交
3951
            return ffp ? ffp->stat.vdps : default_value;
Z
Zhang Rui 已提交
3952
        case FFP_PROP_FLOAT_VIDEO_OUTPUT_FRAMES_PER_SECOND:
Z
Zhang Rui 已提交
3953
            return ffp ? ffp->stat.vfps : default_value;
Z
Zhang Rui 已提交
3954 3955
        case FFP_PROP_FLOAT_PLAYBACK_RATE:
            return ffp ? ffp->pf_playback_rate : default_value;
Z
Zhang Rui 已提交
3956 3957 3958 3959
        case FFP_PROP_FLOAT_AVDELAY:
            return ffp ? ffp->stat.avdelay : default_value;
        case FFP_PROP_FLOAT_AVDIFF:
            return ffp ? ffp->stat.avdiff : default_value;
Z
Zhang Rui 已提交
3960 3961 3962
        default:
            return default_value;
    }
Z
Zhang Rui 已提交
3963 3964
}

Z
Zhang Rui 已提交
3965 3966 3967 3968 3969 3970 3971 3972 3973 3974
void ffp_set_property_float(FFPlayer *ffp, int id, float value)
{
    switch (id) {
        case FFP_PROP_FLOAT_PLAYBACK_RATE:
            ffp_set_playback_rate(ffp, value);
        default:
            return;
    }
}

3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985
int64_t ffp_get_property_int64(FFPlayer *ffp, int id, int64_t default_value)
{
    switch (id) {
        case FFP_PROP_INT64_SELECTED_VIDEO_STREAM:
            if (!ffp || !ffp->is)
                return default_value;
            return ffp->is->video_stream;
        case FFP_PROP_INT64_SELECTED_AUDIO_STREAM:
            if (!ffp || !ffp->is)
                return default_value;
            return ffp->is->audio_stream;
Z
Zhang Rui 已提交
3986 3987 3988 3989 3990 3991 3992 3993 3994 3995
        case FFP_PROP_INT64_VIDEO_DECODER:
            if (!ffp)
                return default_value;
            return ffp->stat.vdec_type;
        case FFP_PROP_INT64_AUDIO_DECODER:
            return FFP_PROPV_DECODER_AVCODEC;

        case FFP_PROP_INT64_VIDEO_CACHED_DURATION:
            if (!ffp)
                return default_value;
Z
Zhang Rui 已提交
3996
            return ffp->stat.video_cache.duration;
Z
Zhang Rui 已提交
3997 3998 3999
        case FFP_PROP_INT64_AUDIO_CACHED_DURATION:
            if (!ffp)
                return default_value;
Z
Zhang Rui 已提交
4000
            return ffp->stat.audio_cache.duration;
Z
Zhang Rui 已提交
4001 4002 4003
        case FFP_PROP_INT64_VIDEO_CACHED_BYTES:
            if (!ffp)
                return default_value;
Z
Zhang Rui 已提交
4004
            return ffp->stat.video_cache.bytes;
Z
Zhang Rui 已提交
4005 4006 4007
        case FFP_PROP_INT64_AUDIO_CACHED_BYTES:
            if (!ffp)
                return default_value;
Z
Zhang Rui 已提交
4008
            return ffp->stat.audio_cache.bytes;
Z
Zhang Rui 已提交
4009 4010 4011
        case FFP_PROP_INT64_VIDEO_CACHED_PACKETS:
            if (!ffp)
                return default_value;
Z
Zhang Rui 已提交
4012
            return ffp->stat.video_cache.packets;
Z
Zhang Rui 已提交
4013 4014 4015
        case FFP_PROP_INT64_AUDIO_CACHED_PACKETS:
            if (!ffp)
                return default_value;
Z
Zhang Rui 已提交
4016
            return ffp->stat.audio_cache.packets;
Z
Zhang Rui 已提交
4017 4018
        case FFP_PROP_INT64_BIT_RATE:
            return ffp ? ffp->stat.bit_rate : default_value;
4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033
        default:
            return default_value;
    }
}

void ffp_set_property_int64(FFPlayer *ffp, int id, int64_t value)
{
    switch (id) {
        // case FFP_PROP_INT64_SELECTED_VIDEO_STREAM:
        // case FFP_PROP_INT64_SELECTED_AUDIO_STREAM:
        default:
            break;
    }
}

Z
Zhang Rui 已提交
4034 4035 4036 4037 4038 4039 4040
IjkMediaMeta *ffp_get_meta_l(FFPlayer *ffp)
{
    if (!ffp)
        return NULL;

    return ffp->meta;
}