Skip to content
Snippets Groups Projects
ffplay.c 131 KiB
Newer Older
  • Learn to ignore specific revisions
  •                                 st_index[AVMEDIA_TYPE_VIDEO],
                                    NULL, 0);
    
        if (!video_disable && !subtitle_disable)
    
            st_index[AVMEDIA_TYPE_SUBTITLE] =
                av_find_best_stream(ic, AVMEDIA_TYPE_SUBTITLE,
    
                                    (st_index[AVMEDIA_TYPE_AUDIO] >= 0 ?
                                     st_index[AVMEDIA_TYPE_AUDIO] :
                                     st_index[AVMEDIA_TYPE_VIDEO]),
                                    NULL, 0);
    
        is->show_mode = show_mode;
    
        if (st_index[AVMEDIA_TYPE_VIDEO] >= 0) {
            AVStream *st = ic->streams[st_index[AVMEDIA_TYPE_VIDEO]];
            AVCodecContext *avctx = st->codec;
    
            AVRational sar = av_guess_sample_aspect_ratio(ic, st, NULL);
            if (avctx->width)
                set_default_window_size(avctx->width, avctx->height, sar);
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        /* open the streams */
    
        if (st_index[AVMEDIA_TYPE_AUDIO] >= 0) {
            stream_component_open(is, st_index[AVMEDIA_TYPE_AUDIO]);
    
    Aneesh Dogra's avatar
    Aneesh Dogra committed
        ret = -1;
    
        if (st_index[AVMEDIA_TYPE_VIDEO] >= 0) {
    
    Aneesh Dogra's avatar
    Aneesh Dogra committed
            ret = stream_component_open(is, st_index[AVMEDIA_TYPE_VIDEO]);
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
        }
    
        if (is->show_mode == SHOW_MODE_NONE)
            is->show_mode = ret >= 0 ? SHOW_MODE_VIDEO : SHOW_MODE_RDFT;
    
        if (st_index[AVMEDIA_TYPE_SUBTITLE] >= 0) {
            stream_component_open(is, st_index[AVMEDIA_TYPE_SUBTITLE]);
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        if (is->video_stream < 0 && is->audio_stream < 0) {
    
            av_log(NULL, AV_LOG_FATAL, "Failed to open file '%s' or configure filtergraph\n",
                   is->filename);
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
            goto fail;
        }
    
    
    Aneesh Dogra's avatar
    Aneesh Dogra committed
        for (;;) {
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
            if (is->abort_request)
                break;
    
            if (is->paused != is->last_paused) {
                is->last_paused = is->paused;
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
                if (is->paused)
    
    Aneesh Dogra's avatar
    Aneesh Dogra committed
                    is->read_pause_return = av_read_pause(ic);
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
                else
                    av_read_play(ic);
    
    #if CONFIG_RTSP_DEMUXER || CONFIG_MMSH_PROTOCOL
            if (is->paused &&
                    (!strcmp(ic->iformat->name, "rtsp") ||
    
                     (ic->pb && !strncmp(input_filename, "mmsh:", 5)))) {
    
                /* wait 10 ms to avoid trying to get another packet */
                /* XXX: horrible */
                SDL_Delay(10);
                continue;
            }
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
            if (is->seek_req) {
    
    Aneesh Dogra's avatar
    Aneesh Dogra committed
                int64_t seek_target = is->seek_pos;
                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;
    // FIXME the +-2 is due to rounding being not done in the correct direction in generation
    
    //      of the seek_pos/seek_rel variables
    
                ret = avformat_seek_file(is->ic, -1, seek_min, seek_target, seek_max, is->seek_flags);
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
                if (ret < 0) {
    
                    av_log(NULL, AV_LOG_ERROR,
                           "%s: error while seeking\n", is->ic->filename);
    
    Aneesh Dogra's avatar
    Aneesh Dogra committed
                } else {
    
                    if (is->audio_stream >= 0) {
                        packet_queue_flush(&is->audioq);
    
                        packet_queue_put(&is->audioq, &flush_pkt);
    
                    if (is->subtitle_stream >= 0) {
                        packet_queue_flush(&is->subtitleq);
    
                        packet_queue_put(&is->subtitleq, &flush_pkt);
    
                    if (is->video_stream >= 0) {
                        packet_queue_flush(&is->videoq);
    
                        packet_queue_put(&is->videoq, &flush_pkt);
    
                    if (is->seek_flags & AVSEEK_FLAG_BYTE) {
    
                       set_clock(&is->extclk, NAN, 0);
    
                       set_clock(&is->extclk, seek_target / (double)AV_TIME_BASE, 0);
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
                }
                is->seek_req = 0;
    
                if (is->paused)
                    step_to_next_frame(is);
    
            if (is->queue_attachments_req) {
    
                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);
    
                    packet_queue_put_nullpacket(&is->videoq, is->video_stream);
    
                is->queue_attachments_req = 0;
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
            /* if the queue are full, no need to read more */
    
                  (is->audioq.size + is->videoq.size + is->subtitleq.size > MAX_QUEUE_SIZE
    
                || (   (is->audioq   .nb_packets > MIN_FRAMES || is->audio_stream < 0 || is->audioq.abort_request)
    
                    && (is->videoq   .nb_packets > MIN_FRAMES || is->video_stream < 0 || is->videoq.abort_request
                        || (is->video_st->disposition & AV_DISPOSITION_ATTACHED_PIC))
    
                    && (is->subtitleq.nb_packets > MIN_FRAMES || is->subtitle_stream < 0 || is->subtitleq.abort_request)))) {
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
                /* wait 10 ms */
    
                SDL_LockMutex(wait_mutex);
                SDL_CondWaitTimeout(is->continue_read_thread, wait_mutex, 10);
                SDL_UnlockMutex(wait_mutex);
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
                continue;
            }
    
                (!is->audio_st || (is->auddec.finished == is->audioq.serial && frame_queue_nb_remaining(&is->sampq) == 0)) &&
    
                (!is->video_st || (is->viddec.finished == is->videoq.serial && frame_queue_nb_remaining(&is->pictq) == 0))) {
    
                if (loop != 1 && (!loop || --loop)) {
                    stream_seek(is, start_time != AV_NOPTS_VALUE ? start_time : 0, 0, 0);
                } else if (autoexit) {
                    ret = AVERROR_EOF;
                    goto fail;
                }
            }
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
            ret = av_read_frame(ic, pkt);
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
            if (ret < 0) {
    
                if ((ret == AVERROR_EOF || avio_feof(ic->pb)) && !is->eof) {
    
                    if (is->video_stream >= 0)
                        packet_queue_put_nullpacket(&is->videoq, is->video_stream);
                    if (is->audio_stream >= 0)
                        packet_queue_put_nullpacket(&is->audioq, is->audio_stream);
                    if (is->subtitle_stream >= 0)
                        packet_queue_put_nullpacket(&is->subtitleq, is->subtitle_stream);
    
                if (ic->pb && ic->pb->error)
    
                SDL_LockMutex(wait_mutex);
                SDL_CondWaitTimeout(is->continue_read_thread, wait_mutex, 10);
                SDL_UnlockMutex(wait_mutex);
    
    Robert Krüger's avatar
    Robert Krüger committed
            /* check if packet is in play range specified by user, then queue, otherwise discard */
    
            stream_start_time = ic->streams[pkt->stream_index]->start_time;
    
            pkt_ts = pkt->pts == AV_NOPTS_VALUE ? pkt->dts : pkt->pts;
    
    Robert Krüger's avatar
    Robert Krüger committed
            pkt_in_play_range = duration == AV_NOPTS_VALUE ||
    
                    (pkt_ts - (stream_start_time != AV_NOPTS_VALUE ? stream_start_time : 0)) *
    
    Robert Krüger's avatar
    Robert Krüger committed
                    av_q2d(ic->streams[pkt->stream_index]->time_base) -
    
    Aneesh Dogra's avatar
    Aneesh Dogra committed
                    (double)(start_time != AV_NOPTS_VALUE ? start_time : 0) / 1000000
                    <= ((double)duration / 1000000);
    
    Robert Krüger's avatar
    Robert Krüger committed
            if (pkt->stream_index == is->audio_stream && pkt_in_play_range) {
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
                packet_queue_put(&is->audioq, pkt);
    
            } else if (pkt->stream_index == is->video_stream && pkt_in_play_range
                       && !(is->video_st->disposition & AV_DISPOSITION_ATTACHED_PIC)) {
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
                packet_queue_put(&is->videoq, pkt);
    
    Robert Krüger's avatar
    Robert Krüger committed
            } else if (pkt->stream_index == is->subtitle_stream && pkt_in_play_range) {
    
                packet_queue_put(&is->subtitleq, pkt);
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
            } else {
                av_free_packet(pkt);
            }
        }
        /* wait until the end */
        while (!is->abort_request) {
            SDL_Delay(100);
        }
    
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
     fail:
        /* close each stream */
        if (is->audio_stream >= 0)
            stream_component_close(is, is->audio_stream);
        if (is->video_stream >= 0)
            stream_component_close(is, is->video_stream);
    
        if (is->subtitle_stream >= 0)
            stream_component_close(is, is->subtitle_stream);
    
        if (ic) {
            avformat_close_input(&ic);
            is->ic = NULL;
    
            event.type = FF_QUIT_EVENT;
            event.user.data1 = is;
            SDL_PushEvent(&event);
        }
    
        SDL_DestroyMutex(wait_mutex);
    
    static VideoState *stream_open(const char *filename, AVInputFormat *iformat)
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    {
        VideoState *is;
    
        is = av_mallocz(sizeof(VideoState));
        if (!is)
            return NULL;
    
        av_strlcpy(is->filename, filename, sizeof(is->filename));
    
    Aneesh Dogra's avatar
    Aneesh Dogra committed
        is->ytop    = 0;
        is->xleft   = 0;
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    
        /* start video display */
    
        if (frame_queue_init(&is->pictq, &is->videoq, VIDEO_PICTURE_QUEUE_SIZE, 1) < 0)
            goto fail;
        if (frame_queue_init(&is->subpq, &is->subtitleq, SUBPICTURE_QUEUE_SIZE, 0) < 0)
            goto fail;
    
        if (frame_queue_init(&is->sampq, &is->audioq, SAMPLE_QUEUE_SIZE, 1) < 0)
            goto fail;
    
        packet_queue_init(&is->videoq);
        packet_queue_init(&is->audioq);
        packet_queue_init(&is->subtitleq);
    
    
        is->continue_read_thread = SDL_CreateCond();
    
    
        init_clock(&is->vidclk, &is->videoq.serial);
        init_clock(&is->audclk, &is->audioq.serial);
        init_clock(&is->extclk, &is->extclk.serial);
    
        is->audio_clock_serial = -1;
    
        is->read_tid     = SDL_CreateThread(read_thread, is);
    
    fail:
            stream_close(is);
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
            return NULL;
        }
        return is;
    }
    
    
    static void stream_cycle_channel(VideoState *is, int codec_type)
    
    {
        AVFormatContext *ic = is->ic;
        int start_index, stream_index;
    
        AVProgram *p = NULL;
        int nb_streams = is->ic->nb_streams;
    
        if (codec_type == AVMEDIA_TYPE_VIDEO) {
            start_index = is->last_video_stream;
            old_index = is->video_stream;
        } else if (codec_type == AVMEDIA_TYPE_AUDIO) {
            start_index = is->last_audio_stream;
            old_index = is->audio_stream;
        } else {
            start_index = is->last_subtitle_stream;
            old_index = is->subtitle_stream;
        }
    
    
        if (codec_type != AVMEDIA_TYPE_VIDEO && is->video_stream != -1) {
            p = av_find_program_from_stream(ic, NULL, is->video_stream);
            if (p) {
                nb_streams = p->nb_stream_indexes;
                for (start_index = 0; start_index < nb_streams; start_index++)
                    if (p->stream_index[start_index] == stream_index)
                        break;
                if (start_index == nb_streams)
                    start_index = -1;
                stream_index = start_index;
            }
        }
    
    
    Aneesh Dogra's avatar
    Aneesh Dogra committed
        for (;;) {
    
                if (codec_type == AVMEDIA_TYPE_SUBTITLE)
    
                    is->last_subtitle_stream = -1;
    
                }
                if (start_index == -1)
                    return;
                stream_index = 0;
    
            st = is->ic->streams[p ? p->stream_index[stream_index] : stream_index];
    
            if (st->codec->codec_type == codec_type) {
    
    Aneesh Dogra's avatar
    Aneesh Dogra committed
                switch (codec_type) {
    
                    if (st->codec->sample_rate != 0 &&
                        st->codec->channels != 0)
    
                case AVMEDIA_TYPE_VIDEO:
                case AVMEDIA_TYPE_SUBTITLE:
    
        if (p && stream_index != -1)
            stream_index = p->stream_index[stream_index];
    
        av_log(NULL, AV_LOG_INFO, "Switch %s stream from #%d to #%d\n",
               av_get_media_type_string(codec_type),
               old_index,
               stream_index);
    
    
        stream_component_close(is, old_index);
    
    static void toggle_full_screen(VideoState *is)
    
    #if defined(__APPLE__) && SDL_VERSION_ATLEAST(1, 2, 14)
    
        /* OS X needs to reallocate the SDL overlays */
    
        int i;
        for (i = 0; i < VIDEO_PICTURE_QUEUE_SIZE; i++)
    
            is->pictq.queue[i].reallocate = 1;
    
        is_full_screen = !is_full_screen;
    
        video_open(is, 1, NULL);
    
    static void toggle_audio_display(VideoState *is)
    
        int bgcolor = SDL_MapRGB(screen->format, 0x00, 0x00, 0x00);
    
        int next = is->show_mode;
        do {
            next = (next + 1) % SHOW_MODE_NB;
        } while (next != is->show_mode && (next == SHOW_MODE_VIDEO && !is->video_st || next != SHOW_MODE_VIDEO && !is->audio_st));
        if (is->show_mode != next) {
            fill_rectangle(screen,
                        is->xleft, is->ytop, is->width, is->height,
                        bgcolor, 1);
            is->force_refresh = 1;
            is->show_mode = next;
        }
    
    static void refresh_loop_wait_event(VideoState *is, SDL_Event *event) {
    
        double remaining_time = 0.0;
        SDL_PumpEvents();
        while (!SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_ALLEVENTS)) {
    
            if (!cursor_hidden && av_gettime_relative() - cursor_last_shown > CURSOR_HIDE_DELAY) {
    
            if (remaining_time > 0.0)
                av_usleep((int64_t)(remaining_time * 1000000.0));
    
            remaining_time = REFRESH_RATE;
            if (is->show_mode != SHOW_MODE_NONE && (!is->paused || is->force_refresh))
                video_refresh(is, &remaining_time);
            SDL_PumpEvents();
    
    static void seek_chapter(VideoState *is, int incr)
    {
        int64_t pos = get_master_clock(is) * AV_TIME_BASE;
        int i;
    
        if (!is->ic->nb_chapters)
            return;
    
        /* find the current chapter */
        for (i = 0; i < is->ic->nb_chapters; i++) {
            AVChapter *ch = is->ic->chapters[i];
            if (av_compare_ts(pos, AV_TIME_BASE_Q, ch->start, ch->time_base) < 0) {
                i--;
                break;
            }
        }
    
        i += incr;
        i = FFMAX(i, 0);
        if (i >= is->ic->nb_chapters)
            return;
    
        av_log(NULL, AV_LOG_VERBOSE, "Seeking to chapter %d.\n", i);
        stream_seek(is, av_rescale_q(is->ic->chapters[i]->start, is->ic->chapters[i]->time_base,
                                     AV_TIME_BASE_Q), 0, 0);
    }
    
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    /* handle an event sent by the GUI */
    
    static void event_loop(VideoState *cur_stream)
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    {
        SDL_Event event;
    
    Aneesh Dogra's avatar
    Aneesh Dogra committed
        for (;;) {
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
            double x;
    
            refresh_loop_wait_event(cur_stream, &event);
    
    Aneesh Dogra's avatar
    Aneesh Dogra committed
            switch (event.type) {
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
            case SDL_KEYDOWN:
    
                    do_exit(cur_stream);
    
    Aneesh Dogra's avatar
    Aneesh Dogra committed
                switch (event.key.keysym.sym) {
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
                case SDLK_ESCAPE:
                case SDLK_q:
    
                    do_exit(cur_stream);
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
                    break;
                case SDLK_f:
    
                    toggle_full_screen(cur_stream);
    
                    cur_stream->force_refresh = 1;
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
                    break;
                case SDLK_p:
                case SDLK_SPACE:
    
                    toggle_pause(cur_stream);
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
                    break;
    
    Aneesh Dogra's avatar
    Aneesh Dogra committed
                case SDLK_s: // S: Step to next frame
    
                    step_to_next_frame(cur_stream);
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
                case SDLK_a:
    
                    stream_cycle_channel(cur_stream, AVMEDIA_TYPE_AUDIO);
    
                    stream_cycle_channel(cur_stream, AVMEDIA_TYPE_VIDEO);
    
                case SDLK_c:
                    stream_cycle_channel(cur_stream, AVMEDIA_TYPE_VIDEO);
                    stream_cycle_channel(cur_stream, AVMEDIA_TYPE_AUDIO);
                    stream_cycle_channel(cur_stream, AVMEDIA_TYPE_SUBTITLE);
                    break;
    
                    stream_cycle_channel(cur_stream, AVMEDIA_TYPE_SUBTITLE);
    
    #if CONFIG_AVFILTER
                    if (cur_stream->show_mode == SHOW_MODE_VIDEO && cur_stream->vfilter_idx < nb_vfilters - 1) {
                        if (++cur_stream->vfilter_idx >= nb_vfilters)
                            cur_stream->vfilter_idx = 0;
                    } else {
                        cur_stream->vfilter_idx = 0;
                        toggle_audio_display(cur_stream);
                    }
    #else
    
                    toggle_audio_display(cur_stream);
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
                    break;
    
                    if (cur_stream->ic->nb_chapters <= 1) {
                        incr = 600.0;
                        goto do_seek;
                    }
                    seek_chapter(cur_stream, 1);
                    break;
    
                    if (cur_stream->ic->nb_chapters <= 1) {
                        incr = -600.0;
                        goto do_seek;
                    }
                    seek_chapter(cur_stream, -1);
                    break;
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
                case SDLK_LEFT:
                    incr = -10.0;
                    goto do_seek;
                case SDLK_RIGHT:
                    incr = 10.0;
                    goto do_seek;
                case SDLK_UP:
                    incr = 60.0;
                    goto do_seek;
                case SDLK_DOWN:
                    incr = -60.0;
                do_seek:
    
                        if (seek_by_bytes) {
    
                            pos = -1;
                            if (pos < 0 && cur_stream->video_stream >= 0)
                                pos = frame_queue_last_pos(&cur_stream->pictq);
    
                            if (pos < 0 && cur_stream->audio_stream >= 0)
                                pos = frame_queue_last_pos(&cur_stream->sampq);
    
                                pos = avio_tell(cur_stream->ic->pb);
    
                            if (cur_stream->ic->bit_rate)
    
                                incr *= cur_stream->ic->bit_rate / 8.0;
    
                            else
                                incr *= 180000.0;
                            pos += incr;
    
                        } else {
                            pos = get_master_clock(cur_stream);
    
                            if (isnan(pos))
                                pos = (double)cur_stream->seek_pos / AV_TIME_BASE;
    
                            pos += incr;
    
                            if (cur_stream->ic->start_time != AV_NOPTS_VALUE && pos < cur_stream->ic->start_time / (double)AV_TIME_BASE)
                                pos = cur_stream->ic->start_time / (double)AV_TIME_BASE;
    
                            stream_seek(cur_stream, (int64_t)(pos * AV_TIME_BASE), (int64_t)(incr * AV_TIME_BASE), 0);
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
                    break;
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
                default:
                    break;
                }
                break;
    
            case SDL_VIDEOEXPOSE:
                cur_stream->force_refresh = 1;
                break;
    
                    do_exit(cur_stream);
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
            case SDL_MOUSEMOTION:
    
                if (cursor_hidden) {
                    SDL_ShowCursor(1);
                    cursor_hidden = 0;
                }
    
                cursor_last_shown = av_gettime_relative();
    
    Aneesh Dogra's avatar
    Aneesh Dogra committed
                if (event.type == SDL_MOUSEBUTTONDOWN) {
                    x = event.button.x;
                } else {
                    if (event.motion.state != SDL_PRESSED)
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
                        break;
    
    Aneesh Dogra's avatar
    Aneesh Dogra committed
                    x = event.motion.x;
    
    Aneesh Dogra's avatar
    Aneesh Dogra committed
                    if (seek_by_bytes || cur_stream->ic->duration <= 0) {
                        uint64_t size =  avio_size(cur_stream->ic->pb);
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
                        stream_seek(cur_stream, size*x/cur_stream->width, 0, 1);
    
    Aneesh Dogra's avatar
    Aneesh Dogra committed
                    } else {
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
                        int64_t ts;
                        int ns, hh, mm, ss;
                        int tns, thh, tmm, tss;
    
    Aneesh Dogra's avatar
    Aneesh Dogra committed
                        tns  = cur_stream->ic->duration / 1000000LL;
                        thh  = tns / 3600;
                        tmm  = (tns % 3600) / 60;
                        tss  = (tns % 60);
                        frac = x / cur_stream->width;
                        ns   = frac * tns;
                        hh   = ns / 3600;
                        mm   = (ns % 3600) / 60;
                        ss   = (ns % 60);
    
                        av_log(NULL, AV_LOG_INFO,
                               "Seek to %2.0f%% (%2d:%02d:%02d) of total duration (%2d:%02d:%02d)       \n", frac*100,
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
                                hh, mm, ss, thh, tmm, tss);
    
    Aneesh Dogra's avatar
    Aneesh Dogra committed
                        ts = frac * cur_stream->ic->duration;
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
                        if (cur_stream->ic->start_time != AV_NOPTS_VALUE)
                            ts += cur_stream->ic->start_time;
                        stream_seek(cur_stream, ts, 0, 0);
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
            case SDL_VIDEORESIZE:
    
                    screen = SDL_SetVideoMode(FFMIN(16383, event.resize.w), event.resize.h, 0,
    
                                              SDL_HWSURFACE|(is_full_screen?SDL_FULLSCREEN:SDL_RESIZABLE)|SDL_ASYNCBLIT|SDL_HWACCEL);
    
                        av_log(NULL, AV_LOG_FATAL, "Failed to set video mode\n");
    
                        do_exit(cur_stream);
                    }
                    screen_width  = cur_stream->width  = screen->w;
                    screen_height = cur_stream->height = screen->h;
    
                    cur_stream->force_refresh = 1;
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
                break;
            case SDL_QUIT:
    
                do_exit(cur_stream);
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
                break;
            case FF_ALLOC_EVENT:
                alloc_picture(event.user.data1);
                break;
            default:
                break;
            }
        }
    }
    
    
    static int opt_frame_size(void *optctx, const char *opt, const char *arg)
    
        av_log(NULL, AV_LOG_WARNING, "Option -s is deprecated, use -video_size.\n");
    
        return opt_default(NULL, "video_size", arg);
    
    static int opt_width(void *optctx, const char *opt, const char *arg)
    
        screen_width = parse_number_or_die(opt, arg, OPT_INT64, 1, INT_MAX);
        return 0;
    
    static int opt_height(void *optctx, const char *opt, const char *arg)
    
        screen_height = parse_number_or_die(opt, arg, OPT_INT64, 1, INT_MAX);
        return 0;
    
    static int opt_format(void *optctx, const char *opt, const char *arg)
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    {
        file_iformat = av_find_input_format(arg);
        if (!file_iformat) {
    
            av_log(NULL, AV_LOG_FATAL, "Unknown input format: %s\n", arg);
    
            return AVERROR(EINVAL);
    
        return 0;
    
    static int opt_frame_pix_fmt(void *optctx, const char *opt, const char *arg)
    
        av_log(NULL, AV_LOG_WARNING, "Option -pix_fmt is deprecated, use -pixel_format.\n");
    
        return opt_default(NULL, "pixel_format", arg);
    
    static int opt_sync(void *optctx, const char *opt, const char *arg)
    
    {
        if (!strcmp(arg, "audio"))
            av_sync_type = AV_SYNC_AUDIO_MASTER;
        else if (!strcmp(arg, "video"))
            av_sync_type = AV_SYNC_VIDEO_MASTER;
        else if (!strcmp(arg, "ext"))
            av_sync_type = AV_SYNC_EXTERNAL_CLOCK;
    
            av_log(NULL, AV_LOG_ERROR, "Unknown value for %s: %s\n", opt, arg);
    
    static int opt_seek(void *optctx, const char *opt, const char *arg)
    
        start_time = parse_time_or_die(opt, arg, 1);
        return 0;
    
    static int opt_duration(void *optctx, const char *opt, const char *arg)
    
    Robert Krüger's avatar
    Robert Krüger committed
    {
        duration = parse_time_or_die(opt, arg, 1);
        return 0;
    }
    
    
    static int opt_show_mode(void *optctx, const char *opt, const char *arg)
    
    {
        show_mode = !strcmp(arg, "video") ? SHOW_MODE_VIDEO :
                    !strcmp(arg, "waves") ? SHOW_MODE_WAVES :
                    !strcmp(arg, "rdft" ) ? SHOW_MODE_RDFT  :
                    parse_number_or_die(opt, arg, OPT_INT, 0, SHOW_MODE_NB-1);
        return 0;
    }
    
    
    static void opt_input_file(void *optctx, const char *filename)
    
            av_log(NULL, AV_LOG_FATAL,
                   "Argument '%s' provided as input filename, but '%s' was already specified.\n",
    
                    filename, input_filename);
    
        }
        if (!strcmp(filename, "-"))
            filename = "pipe:";
        input_filename = filename;
    }
    
    
    static int opt_codec(void *optctx, const char *opt, const char *arg)
    
       const char *spec = strchr(opt, ':');
       if (!spec) {
    
           av_log(NULL, AV_LOG_ERROR,
                  "No media specifier was specified in '%s' in option '%s'\n",
    
                   arg, opt);
           return AVERROR(EINVAL);
       }
       spec++;
       switch (spec[0]) {
       case 'a' :    audio_codec_name = arg; break;
       case 's' : subtitle_codec_name = arg; break;
       case 'v' :    video_codec_name = arg; break;
       default:
    
           av_log(NULL, AV_LOG_ERROR,
                  "Invalid media specifier '%s' in option '%s'\n", spec, opt);
    
    #include "cmdutils_common_opts.h"
    
        { "x", HAS_ARG, { .func_arg = opt_width }, "force displayed width", "width" },
        { "y", HAS_ARG, { .func_arg = opt_height }, "force displayed height", "height" },
        { "s", HAS_ARG | OPT_VIDEO, { .func_arg = opt_frame_size }, "set frame size (WxH or abbreviation)", "size" },
        { "fs", OPT_BOOL, { &is_full_screen }, "force full screen" },
        { "an", OPT_BOOL, { &audio_disable }, "disable audio" },
        { "vn", OPT_BOOL, { &video_disable }, "disable video" },
    
        { "sn", OPT_BOOL, { &subtitle_disable }, "disable subtitling" },
    
        { "ast", OPT_STRING | HAS_ARG | OPT_EXPERT, { &wanted_stream_spec[AVMEDIA_TYPE_AUDIO] }, "select desired audio stream", "stream_specifier" },
        { "vst", OPT_STRING | HAS_ARG | OPT_EXPERT, { &wanted_stream_spec[AVMEDIA_TYPE_VIDEO] }, "select desired video stream", "stream_specifier" },
        { "sst", OPT_STRING | HAS_ARG | OPT_EXPERT, { &wanted_stream_spec[AVMEDIA_TYPE_SUBTITLE] }, "select desired subtitle stream", "stream_specifier" },
    
        { "ss", HAS_ARG, { .func_arg = opt_seek }, "seek to a given position in seconds", "pos" },
        { "t", HAS_ARG, { .func_arg = opt_duration }, "play  \"duration\" seconds of audio/video", "duration" },
        { "bytes", OPT_INT | HAS_ARG, { &seek_by_bytes }, "seek by bytes 0=off 1=on -1=auto", "val" },
        { "nodisp", OPT_BOOL, { &display_disable }, "disable graphical display" },
        { "f", HAS_ARG, { .func_arg = opt_format }, "force format", "fmt" },
        { "pix_fmt", HAS_ARG | OPT_EXPERT | OPT_VIDEO, { .func_arg = opt_frame_pix_fmt }, "set pixel format", "format" },
        { "stats", OPT_BOOL | OPT_EXPERT, { &show_status }, "show status", "" },
        { "fast", OPT_BOOL | OPT_EXPERT, { &fast }, "non spec compliant optimizations", "" },
        { "genpts", OPT_BOOL | OPT_EXPERT, { &genpts }, "generate pts", "" },
        { "drp", OPT_INT | HAS_ARG | OPT_EXPERT, { &decoder_reorder_pts }, "let decoder reorder pts 0=off 1=on -1=auto", ""},
        { "lowres", OPT_INT | HAS_ARG | OPT_EXPERT, { &lowres }, "", "" },
        { "sync", HAS_ARG | OPT_EXPERT, { .func_arg = opt_sync }, "set audio-video sync. type (type=audio/video/ext)", "type" },
        { "autoexit", OPT_BOOL | OPT_EXPERT, { &autoexit }, "exit at the end", "" },
        { "exitonkeydown", OPT_BOOL | OPT_EXPERT, { &exit_on_keydown }, "exit on key down", "" },
        { "exitonmousedown", OPT_BOOL | OPT_EXPERT, { &exit_on_mousedown }, "exit on mouse down", "" },
        { "loop", OPT_INT | HAS_ARG | OPT_EXPERT, { &loop }, "set number of times the playback shall be looped", "loop count" },
        { "framedrop", OPT_BOOL | OPT_EXPERT, { &framedrop }, "drop frames when cpu is too slow", "" },
        { "infbuf", OPT_BOOL | OPT_EXPERT, { &infinite_buffer }, "don't limit the input buffer size (useful with realtime streams)", "" },
        { "window_title", OPT_STRING | HAS_ARG, { &window_title }, "set window title", "window title" },
    
    #if CONFIG_AVFILTER
    
        { "vf", OPT_EXPERT | HAS_ARG, { .func_arg = opt_add_vfilter }, "set video filters", "filter_graph" },
    
    Marton Balint's avatar
    Marton Balint committed
        { "af", OPT_STRING | HAS_ARG, { &afilters }, "set audio filters", "filter_graph" },
    
        { "rdftspeed", OPT_INT | HAS_ARG| OPT_AUDIO | OPT_EXPERT, { &rdftspeed }, "rdft speed", "msecs" },
        { "showmode", HAS_ARG, { .func_arg = opt_show_mode}, "select show mode (0 = video, 1 = waves, 2 = RDFT)", "mode" },
        { "default", HAS_ARG | OPT_AUDIO | OPT_VIDEO | OPT_EXPERT, { .func_arg = opt_default }, "generic catch all option", "" },
        { "i", OPT_BOOL, { &dummy}, "read specified file", "input_file"},
    
        { "codec", HAS_ARG, { .func_arg = opt_codec}, "force decoder", "decoder_name" },
        { "acodec", HAS_ARG | OPT_STRING | OPT_EXPERT, {    &audio_codec_name }, "force audio decoder",    "decoder_name" },
        { "scodec", HAS_ARG | OPT_STRING | OPT_EXPERT, { &subtitle_codec_name }, "force subtitle decoder", "decoder_name" },
        { "vcodec", HAS_ARG | OPT_STRING | OPT_EXPERT, {    &video_codec_name }, "force video decoder",    "decoder_name" },
    
        { "autorotate", OPT_BOOL, { &autorotate }, "automatically rotate video", "" },
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        { NULL, },
    };
    
    
    static void show_usage(void)
    
        av_log(NULL, AV_LOG_INFO, "Simple media player\n");
        av_log(NULL, AV_LOG_INFO, "usage: %s [options] input_file\n", program_name);
        av_log(NULL, AV_LOG_INFO, "\n");
    
    void show_help_default(const char *opt, const char *arg)
    
        av_log_set_callback(log_callback_help);
    
        show_usage();
    
        show_help_options(options, "Main options:", 0, OPT_EXPERT, 0);
        show_help_options(options, "Advanced options:", OPT_EXPERT, 0, 0);
    
        show_help_children(avcodec_get_class(), AV_OPT_FLAG_DECODING_PARAM);
        show_help_children(avformat_get_class(), AV_OPT_FLAG_DECODING_PARAM);
    
    #if !CONFIG_AVFILTER
    
        show_help_children(sws_get_class(), AV_OPT_FLAG_ENCODING_PARAM);
    
    #else
        show_help_children(avfilter_get_class(), AV_OPT_FLAG_FILTERING_PARAM);
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        printf("\nWhile playing:\n"
               "q, ESC              quit\n"
               "f                   toggle full screen\n"
               "p, SPC              pause\n"
    
               "a                   cycle audio channel in the current program\n"
    
               "t                   cycle subtitle channel in the current program\n"
    
               "w                   cycle video filters or show modes\n"
    
               "s                   activate frame-step mode\n"
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
               "left/right          seek backward/forward 10 seconds\n"
               "down/up             seek backward/forward 1 minute\n"
    
               "page down/page up   seek backward/forward 10 minutes\n"
    
               "mouse click         seek to percentage in file corresponding to fraction of width\n"
    
    static int lockmgr(void **mtx, enum AVLockOp op)
    {
       switch(op) {
          case AV_LOCK_CREATE:
              *mtx = SDL_CreateMutex();
              if(!*mtx)
                  return 1;
              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;
    }
    
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    /* Called from the main */
    int main(int argc, char **argv)
    {
    
        char dummy_videodriver[] = "SDL_VIDEODRIVER=dummy";
    
        av_log_set_flags(AV_LOG_SKIP_REPEATED);
    
        parse_loglevel(argc, argv, options);
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        /* register all codecs, demux and protocols */
    
    Luca Abeni's avatar
    Luca Abeni committed
        avdevice_register_all();
    
    #if CONFIG_AVFILTER
        avfilter_register_all();
    #endif
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        av_register_all();
    
        avformat_network_init();
    
        signal(SIGINT , sigterm_handler); /* Interrupt (ANSI).    */
        signal(SIGTERM, sigterm_handler); /* Termination (ANSI).  */
    
    
        show_banner(argc, argv, options);
    
        parse_options(NULL, argc, argv, options, opt_input_file);
    
            av_log(NULL, AV_LOG_FATAL, "An input file must be specified\n");
            av_log(NULL, AV_LOG_FATAL,
                   "Use -h to get full help or, even better, run 'man %s'\n", program_name);
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    
        if (display_disable) {
            video_disable = 1;
        }
    
        flags = SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER;
    
        if (audio_disable)
            flags &= ~SDL_INIT_AUDIO;
    
        if (display_disable)
            SDL_putenv(dummy_videodriver); /* For the event queue, we always need a video driver. */
    
    #if !defined(_WIN32) && !defined(__APPLE__)
    
        flags |= SDL_INIT_EVENTTHREAD; /* Not supported on Windows or Mac OS X */
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        if (SDL_Init (flags)) {
    
            av_log(NULL, AV_LOG_FATAL, "Could not initialize SDL - %s\n", SDL_GetError());
            av_log(NULL, AV_LOG_FATAL, "(Did you set the DISPLAY variable?)\n");
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
            exit(1);
        }
    
        if (!display_disable) {
    
            const SDL_VideoInfo *vi = SDL_GetVideoInfo();
            fs_screen_width = vi->current_w;
            fs_screen_height = vi->current_h;
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        }
    
        SDL_EventState(SDL_ACTIVEEVENT, SDL_IGNORE);
        SDL_EventState(SDL_SYSWMEVENT, SDL_IGNORE);
        SDL_EventState(SDL_USEREVENT, SDL_IGNORE);
    
    
        if (av_lockmgr_register(lockmgr)) {
    
            av_log(NULL, AV_LOG_FATAL, "Could not initialize lock manager!\n");
    
        av_init_packet(&flush_pkt);
    
    Luca Barbato's avatar
    Luca Barbato committed
        flush_pkt.data = (uint8_t *)&flush_pkt;
    
        is = stream_open(input_filename, file_iformat);
        if (!is) {
    
            av_log(NULL, AV_LOG_FATAL, "Failed to initialize VideoState!\n");
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    
        /* never returns */
    
        return 0;
    }