X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=avplay.c;h=7437bd615c55089fc61a01c4957acc0609725561;hb=161a301d44274645c2272855dac3e4664f935603;hp=ead79f3c088beb9ad270618dfbc4db4e82864979;hpb=5e3f9979fae32fe837dab6cff5bde7de3c387611;p=ffmpeg diff --git a/avplay.c b/avplay.c index ead79f3c088..7437bd615c5 100644 --- a/avplay.c +++ b/avplay.c @@ -23,8 +23,11 @@ #include #include #include +#include + #include "libavutil/avstring.h" #include "libavutil/colorspace.h" +#include "libavutil/display.h" #include "libavutil/mathematics.h" #include "libavutil/pixdesc.h" #include "libavutil/imgutils.h" @@ -41,7 +44,6 @@ #if CONFIG_AVFILTER # include "libavfilter/avfilter.h" -# include "libavfilter/avfiltergraph.h" # include "libavfilter/buffersink.h" # include "libavfilter/buffersrc.h" #endif @@ -84,7 +86,7 @@ const int program_birth_year = 2003; /* NOTE: the size must be big enough to compensate the hardware audio buffersize size */ #define SAMPLE_ARRAY_SIZE (2 * 65536) -static int sws_flags = SWS_BICUBIC; +static int64_t sws_flags = SWS_BICUBIC; typedef struct PacketQueue { AVPacketList *first_pkt, *last_pkt; @@ -99,18 +101,16 @@ typedef struct PacketQueue { #define SUBPICTURE_QUEUE_SIZE 4 typedef struct VideoPicture { - double pts; ///< presentation time stamp for this picture - double target_clock; ///< av_gettime() time at which this should be displayed ideally - int64_t pos; ///< byte position in file + double pts; // presentation timestamp for this picture + double target_clock; // av_gettime_relative() time at which this should be displayed ideally + int64_t pos; // byte position in file SDL_Overlay *bmp; int width, height; /* source height & width */ int allocated; int reallocate; - enum PixelFormat pix_fmt; + enum AVPixelFormat pix_fmt; -#if CONFIG_AVFILTER - AVFilterBufferRef *picref; -#endif + AVRational sar; } VideoPicture; typedef struct SubPicture { @@ -164,8 +164,10 @@ typedef struct VideoState { enum AVSampleFormat sdl_sample_fmt; uint64_t sdl_channel_layout; int sdl_channels; + int sdl_sample_rate; enum AVSampleFormat resample_sample_fmt; uint64_t resample_channel_layout; + int resample_sample_rate; AVAudioResampleContext *avr; AVFrame *frame; @@ -191,13 +193,13 @@ typedef struct VideoState { double frame_timer; double frame_last_pts; double frame_last_delay; - double video_clock; ///< pts of last decoded frame / predicted pts of next decoded frame + double video_clock; // pts of last decoded frame / predicted pts of next decoded frame int video_stream; AVStream *video_st; PacketQueue videoq; - double video_current_pts; ///< current displayed pts (different from video_clock if frame fifos are used) - double video_current_pts_drift; ///< video_current_pts - time (av_gettime) at which we updated video_current_pts - used to have running video pts - int64_t video_current_pos; ///< current displayed file pos + double video_current_pts; // current displayed pts (different from video_clock if frame fifos are used) + double video_current_pts_drift; // video_current_pts - time (av_gettime_relative) at which we updated video_current_pts - used to have running video pts + int64_t video_current_pos; // current displayed file pos VideoPicture pictq[VIDEO_PICTURE_QUEUE_SIZE]; int pictq_size, pictq_rindex, pictq_windex; SDL_mutex *pictq_mutex; @@ -213,10 +215,8 @@ typedef struct VideoState { PtsCorrectionContext pts_ctx; #if CONFIG_AVFILTER - AVFilterContext *in_video_filter; ///< the first filter in the video chain - AVFilterContext *out_video_filter; ///< the last filter in the video chain - int use_dr1; - FrameBuffer *buffer_pool; + AVFilterContext *in_video_filter; // the first filter in the video chain + AVFilterContext *out_video_filter; // the last filter in the video chain #endif float skip_frames; @@ -245,8 +245,6 @@ static int show_status = 1; static int av_sync_type = AV_SYNC_AUDIO_MASTER; static int64_t start_time = AV_NOPTS_VALUE; static int64_t duration = AV_NOPTS_VALUE; -static int debug = 0; -static int debug_mv = 0; static int step = 0; static int workaround_bugs = 1; static int fast = 0; @@ -257,7 +255,7 @@ static enum AVDiscard skip_idct = AVDISCARD_DEFAULT; static enum AVDiscard skip_loop_filter = AVDISCARD_DEFAULT; static int error_concealment = 3; static int decoder_reorder_pts = -1; -static int autoexit; +static int noautoexit; static int exit_on_keydown; static int exit_on_mousedown; static int loop = 1; @@ -268,6 +266,7 @@ static int rdftspeed = 20; #if CONFIG_AVFILTER static char *vfilters = NULL; #endif +static int autorotate = 1; /* current context */ static int is_full_screen; @@ -654,10 +653,10 @@ static void video_image_display(VideoState *is) vp = &is->pictq[is->pictq_rindex]; if (vp->bmp) { #if CONFIG_AVFILTER - if (vp->picref->video->pixel_aspect.num == 0) + if (!vp->sar.num) aspect_ratio = 0; else - aspect_ratio = av_q2d(vp->picref->video->pixel_aspect); + aspect_ratio = av_q2d(vp->sar); #else /* XXX: use variable in the frame */ @@ -757,8 +756,8 @@ static void video_audio_display(VideoState *s) /* to be more precise, we take into account the time spent since the last buffer computation */ if (audio_callback_time) { - time_diff = av_gettime() - audio_callback_time; - delay -= (time_diff * s->audio_st->codec->sample_rate) / 1000000; + time_diff = av_gettime_relative() - audio_callback_time; + delay -= (time_diff * s->sdl_sample_rate) / 1000000; } delay += 2 * data_used; @@ -851,7 +850,8 @@ static void video_audio_display(VideoState *s) } av_rdft_calc(s->rdft, data[ch]); } - // least efficient way to do this, we should of course directly access it but its more than fast enough + /* Least efficient way to do this, we should of course + * directly access it but it is more than fast enough. */ for (y = 0; y < s->height; y++) { double w = 1 / sqrt(nb_freq); int a = sqrt(w * sqrt(data[0][2 * y + 0] * data[0][2 * y + 0] + data[0][2 * y + 1] * data[0][2 * y + 1])); @@ -960,7 +960,7 @@ static double get_audio_clock(VideoState *is) hw_buf_size = audio_write_get_buf_size(is); bytes_per_sec = 0; if (is->audio_st) { - bytes_per_sec = is->audio_st->codec->sample_rate * is->sdl_channels * + bytes_per_sec = is->sdl_sample_rate * is->sdl_channels * av_get_bytes_per_sample(is->sdl_sample_fmt); } if (bytes_per_sec) @@ -974,7 +974,7 @@ static double get_video_clock(VideoState *is) if (is->paused) { return is->video_current_pts; } else { - return is->video_current_pts_drift + av_gettime() / 1000000.0; + return is->video_current_pts_drift + av_gettime_relative() / 1000000.0; } } @@ -982,7 +982,7 @@ static double get_video_clock(VideoState *is) static double get_external_clock(VideoState *is) { int64_t ti; - ti = av_gettime(); + ti = av_gettime_relative(); return is->external_clock + ((ti - is->external_clock_time) * 1e-6); } @@ -1024,18 +1024,18 @@ static void stream_seek(VideoState *is, int64_t pos, int64_t rel, int seek_by_by static void stream_pause(VideoState *is) { if (is->paused) { - is->frame_timer += av_gettime() / 1000000.0 + is->video_current_pts_drift - is->video_current_pts; + is->frame_timer += av_gettime_relative() / 1000000.0 + is->video_current_pts_drift - is->video_current_pts; if (is->read_pause_return != AVERROR(ENOSYS)) { - is->video_current_pts = is->video_current_pts_drift + av_gettime() / 1000000.0; + is->video_current_pts = is->video_current_pts_drift + av_gettime_relative() / 1000000.0; } - is->video_current_pts_drift = is->video_current_pts - av_gettime() / 1000000.0; + is->video_current_pts_drift = is->video_current_pts - av_gettime_relative() / 1000000.0; } is->paused = !is->paused; } static double compute_target_time(double frame_current_pts, VideoState *is) { - double delay, sync_threshold, diff; + double delay, sync_threshold, diff = 0; /* compute nominal delay */ delay = frame_current_pts - is->frame_last_pts; @@ -1067,7 +1067,7 @@ static double compute_target_time(double frame_current_pts, VideoState *is) } is->frame_timer += delay; - av_dlog(NULL, "video: delay=%0.3f pts=%0.3f A-V=%f\n", + av_log(NULL, AV_LOG_TRACE, "video: delay=%0.3f pts=%0.3f A-V=%f\n", delay, frame_current_pts, -diff); return is->frame_timer; @@ -1086,7 +1086,7 @@ retry: if (is->pictq_size == 0) { // nothing to do, no picture to display in the que } else { - double time = av_gettime() / 1000000.0; + double time = av_gettime_relative() / 1000000.0; double next_target; /* dequeue the picture */ vp = &is->pictq[is->pictq_rindex]; @@ -1192,7 +1192,7 @@ retry: int aqsize, vqsize, sqsize; double av_diff; - cur_time = av_gettime(); + cur_time = av_gettime_relative(); if (!last_time || (cur_time - last_time) >= 30000) { aqsize = 0; vqsize = 0; @@ -1227,9 +1227,6 @@ static void stream_close(VideoState *is) /* free all pictures */ for (i = 0; i < VIDEO_PICTURE_QUEUE_SIZE; i++) { vp = &is->pictq[i]; -#if CONFIG_AVFILTER - avfilter_unref_bufferp(&vp->picref); -#endif if (vp->bmp) { SDL_FreeYUVOverlay(vp->bmp); vp->bmp = NULL; @@ -1253,9 +1250,6 @@ static void do_exit(void) cur_stream = NULL; } uninit_opts(); -#if CONFIG_AVFILTER - avfilter_uninit(); -#endif avformat_network_deinit(); if (show_status) printf("\n"); @@ -1277,8 +1271,6 @@ static void alloc_picture(void *opaque) SDL_FreeYUVOverlay(vp->bmp); #if CONFIG_AVFILTER - avfilter_unref_bufferp(&vp->picref); - vp->width = is->out_video_filter->inputs[0]->w; vp->height = is->out_video_filter->inputs[0]->h; vp->pix_fmt = is->out_video_filter->inputs[0]->format; @@ -1306,17 +1298,15 @@ static void alloc_picture(void *opaque) SDL_UnlockMutex(is->pictq_mutex); } -/** - * - * @param pts the dts of the pkt / pts of the frame and guessed if not known - */ +/* The 'pts' parameter is the dts of the packet / pts of the frame and + * guessed if not known. */ static int queue_picture(VideoState *is, AVFrame *src_frame, double pts, int64_t pos) { VideoPicture *vp; #if CONFIG_AVFILTER AVPicture pict_src; #else - int dst_pix_fmt = PIX_FMT_YUV420P; + int dst_pix_fmt = AV_PIX_FMT_YUV420P; #endif /* wait until we have space to put a new picture */ SDL_LockMutex(is->pictq_mutex); @@ -1335,6 +1325,8 @@ static int queue_picture(VideoState *is, AVFrame *src_frame, double pts, int64_t vp = &is->pictq[is->pictq_windex]; + vp->sar = src_frame->sample_aspect_ratio; + /* alloc or resize hardware picture buffer */ if (!vp->bmp || vp->reallocate || #if CONFIG_AVFILTER @@ -1369,10 +1361,6 @@ static int queue_picture(VideoState *is, AVFrame *src_frame, double pts, int64_t /* if the frame is not skipped, then display it */ if (vp->bmp) { AVPicture pict = { { 0 } }; -#if CONFIG_AVFILTER - avfilter_unref_bufferp(&vp->picref); - vp->picref = src_frame->opaque; -#endif /* get a pointer on the bitmap */ SDL_LockYUVOverlay (vp->bmp); @@ -1398,11 +1386,11 @@ static int queue_picture(VideoState *is, AVFrame *src_frame, double pts, int64_t av_picture_copy(&pict, &pict_src, vp->pix_fmt, vp->width, vp->height); #else - sws_flags = av_get_int(sws_opts, "sws_flags", NULL); + av_opt_get_int(sws_opts, "sws_flags", 0, &sws_flags); is->img_convert_ctx = sws_getCachedContext(is->img_convert_ctx, vp->width, vp->height, vp->pix_fmt, vp->width, vp->height, dst_pix_fmt, sws_flags, NULL, NULL, NULL); - if (is->img_convert_ctx == NULL) { + if (!is->img_convert_ctx) { fprintf(stderr, "Cannot initialize the conversion context\n"); exit(1); } @@ -1427,13 +1415,12 @@ static int queue_picture(VideoState *is, AVFrame *src_frame, double pts, int64_t return 0; } -/** - * compute the exact PTS for the picture if it is omitted in the stream - * @param pts1 the dts of the pkt / pts of the frame - */ +/* Compute the exact PTS for the picture if it is omitted in the stream. + * The 'pts1' parameter is the dts of the packet / pts of the frame. */ static int output_picture2(VideoState *is, AVFrame *src_frame, double pts1, int64_t pos) { double frame_delay, pts; + int ret; pts = pts1; @@ -1450,7 +1437,9 @@ static int output_picture2(VideoState *is, AVFrame *src_frame, double pts1, int6 frame_delay += src_frame->repeat_pict * (frame_delay * 0.5); is->video_clock += frame_delay; - return queue_picture(is, src_frame, pts, pos); + ret = queue_picture(is, src_frame, pts, pos); + av_frame_unref(src_frame); + return ret; } static int get_video_frame(VideoState *is, AVFrame *frame, int64_t *pts, AVPacket *pkt) @@ -1477,7 +1466,7 @@ static int get_video_frame(VideoState *is, AVFrame *frame, int64_t *pts, AVPacke init_pts_correction(&is->pts_ctx); is->frame_last_pts = AV_NOPTS_VALUE; is->frame_last_delay = 0; - is->frame_timer = (double)av_gettime() / 1000000.0; + is->frame_timer = (double)av_gettime_relative() / 1000000.0; is->skip_frames = 1; is->skip_frames_index = 0; return 0; @@ -1497,13 +1486,16 @@ static int get_video_frame(VideoState *is, AVFrame *frame, int64_t *pts, AVPacke if (*pts == AV_NOPTS_VALUE) { *pts = 0; } + if (is->video_st->sample_aspect_ratio.num) { + frame->sample_aspect_ratio = is->video_st->sample_aspect_ratio; + } is->skip_frames_index += 1; if (is->skip_frames_index >= is->skip_frames) { is->skip_frames_index -= FFMAX(is->skip_frames, 1.0); return 1; } - + av_frame_unref(frame); } return 0; } @@ -1514,10 +1506,10 @@ static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const c char sws_flags_str[128]; char buffersrc_args[256]; int ret; - AVFilterContext *filt_src = NULL, *filt_out = NULL, *filt_format; + AVFilterContext *filt_src = NULL, *filt_out = NULL, *last_filter; AVCodecContext *codec = is->video_st->codec; - snprintf(sws_flags_str, sizeof(sws_flags_str), "flags=%d", sws_flags); + snprintf(sws_flags_str, sizeof(sws_flags_str), "flags=%"PRId64, sws_flags); graph->scale_sws_opts = av_strdup(sws_flags_str); snprintf(buffersrc_args, sizeof(buffersrc_args), "%d:%d:%d:%d:%d:%d:%d", @@ -1536,13 +1528,43 @@ static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const c "out", NULL, NULL, graph)) < 0) return ret; - if ((ret = avfilter_graph_create_filter(&filt_format, - avfilter_get_by_name("format"), - "format", "yuv420p", NULL, graph)) < 0) - return ret; - if ((ret = avfilter_link(filt_format, 0, filt_out, 0)) < 0) - return ret; - + 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 */ +#define INSERT_FILT(name, arg) do { \ + AVFilterContext *filt_ctx; \ + \ + ret = avfilter_graph_create_filter(&filt_ctx, \ + avfilter_get_by_name(name), \ + "avplay_" name, arg, NULL, graph); \ + if (ret < 0) \ + return ret; \ + \ + ret = avfilter_link(filt_ctx, 0, last_filter, 0); \ + if (ret < 0) \ + return ret; \ + \ + last_filter = filt_ctx; \ +} while (0) + + INSERT_FILT("format", "yuv420p"); + + if (autorotate) { + uint8_t* displaymatrix = av_stream_get_side_data(is->video_st, + AV_PKT_DATA_DISPLAYMATRIX, NULL); + if (displaymatrix) { + double rot = av_display_rotation_get((int32_t*) displaymatrix); + if (rot < -135 || rot > 135) { + INSERT_FILT("vflip", NULL); + INSERT_FILT("hflip", NULL); + } else if (rot < -45) { + INSERT_FILT("transpose", "dir=clock"); + } else if (rot > 45) { + INSERT_FILT("transpose", "dir=cclock"); + } + } + } if (vfilters) { AVFilterInOut *outputs = avfilter_inout_alloc(); @@ -1554,14 +1576,14 @@ static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const c outputs->next = NULL; inputs->name = av_strdup("out"); - inputs->filter_ctx = filt_format; + inputs->filter_ctx = last_filter; inputs->pad_idx = 0; inputs->next = NULL; if ((ret = avfilter_graph_parse(graph, vfilters, inputs, outputs, NULL)) < 0) return ret; } else { - if ((ret = avfilter_link(filt_src, 0, filt_format, 0)) < 0) + if ((ret = avfilter_link(filt_src, 0, last_filter, 0)) < 0) return ret; } @@ -1571,13 +1593,6 @@ static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const c is->in_video_filter = filt_src; is->out_video_filter = filt_out; - if (codec->codec->capabilities & CODEC_CAP_DR1) { - is->use_dr1 = 1; - codec->get_buffer = codec_get_buffer; - codec->release_buffer = codec_release_buffer; - codec->opaque = &is->buffer_pool; - } - return ret; } @@ -1587,7 +1602,7 @@ static int video_thread(void *arg) { AVPacket pkt = { 0 }; VideoState *is = arg; - AVFrame *frame = avcodec_alloc_frame(); + AVFrame *frame = av_frame_alloc(); int64_t pts_int; double pts; int ret; @@ -1595,9 +1610,12 @@ static int video_thread(void *arg) #if CONFIG_AVFILTER AVFilterGraph *graph = avfilter_graph_alloc(); AVFilterContext *filt_out = NULL, *filt_in = NULL; - int64_t pos; int last_w = is->video_st->codec->width; int last_h = is->video_st->codec->height; + if (!graph) { + av_frame_free(&frame); + return AVERROR(ENOMEM); + } if ((ret = configure_video_filters(graph, is, vfilters)) < 0) goto the_end; @@ -1605,9 +1623,15 @@ static int video_thread(void *arg) filt_out = is->out_video_filter; #endif + if (!frame) { +#if CONFIG_AVFILTER + avfilter_graph_free(&graph); +#endif + return AVERROR(ENOMEM); + } + for (;;) { #if CONFIG_AVFILTER - AVFilterBufferRef *picref; AVRational tb; #endif while (is->paused && !is->videoq.abort_request) @@ -1625,7 +1649,7 @@ static int video_thread(void *arg) #if CONFIG_AVFILTER if ( last_w != is->video_st->codec->width || last_h != is->video_st->codec->height) { - av_dlog(NULL, "Changing size %dx%d -> %dx%d\n", last_w, last_h, + av_log(NULL, AV_LOG_TRACE, "Changing size %dx%d -> %dx%d\n", last_w, last_h, is->video_st->codec->width, is->video_st->codec->height); avfilter_graph_free(&graph); graph = avfilter_graph_alloc(); @@ -1638,48 +1662,29 @@ static int video_thread(void *arg) } frame->pts = pts_int; - if (is->use_dr1) { - FrameBuffer *buf = frame->opaque; - AVFilterBufferRef *fb = avfilter_get_video_buffer_ref_from_arrays( - frame->data, frame->linesize, - AV_PERM_READ | AV_PERM_PRESERVE, - frame->width, frame->height, - frame->format); - - avfilter_copy_frame_props(fb, frame); - fb->buf->priv = buf; - fb->buf->free = filter_release_buffer; - - buf->refcount++; - av_buffersrc_buffer(filt_in, fb); - - } else - av_buffersrc_write_frame(filt_in, frame); + ret = av_buffersrc_add_frame(filt_in, frame); + if (ret < 0) + goto the_end; while (ret >= 0) { - ret = av_buffersink_read(filt_out, &picref); + ret = av_buffersink_get_frame(filt_out, frame); if (ret < 0) { ret = 0; break; } - avfilter_copy_buf_props(frame, picref); - - pts_int = picref->pts; + pts_int = frame->pts; tb = filt_out->inputs[0]->time_base; - pos = picref->pos; - frame->opaque = picref; - if (av_cmp_q(tb, is->video_st->time_base)) { av_unused int64_t pts1 = pts_int; pts_int = av_rescale_q(pts_int, tb, is->video_st->time_base); - av_dlog(NULL, "video_thread(): " + av_log(NULL, AV_LOG_TRACE, "video_thread(): " "tb:%d/%d pts:%"PRId64" -> tb:%d/%d pts:%"PRId64"\n", tb.num, tb.den, pts1, is->video_st->time_base.num, is->video_st->time_base.den, pts_int); } pts = pts_int * av_q2d(is->video_st->time_base); - ret = output_picture2(is, frame, pts, pos); + ret = output_picture2(is, frame, pts, 0); } #else pts = pts_int * av_q2d(is->video_st->time_base); @@ -1689,6 +1694,7 @@ static int video_thread(void *arg) if (ret < 0) goto the_end; + if (step) if (cur_stream) stream_pause(cur_stream); @@ -1699,7 +1705,7 @@ static int video_thread(void *arg) avfilter_graph_free(&graph); #endif av_free_packet(&pkt); - avcodec_free_frame(&frame); + av_frame_free(&frame); return 0; } @@ -1821,7 +1827,7 @@ static int synchronize_audio(VideoState *is, short *samples, avg_diff = is->audio_diff_cum * (1.0 - is->audio_diff_avg_coef); if (fabs(avg_diff) >= is->audio_diff_threshold) { - wanted_size = samples_size + ((int)(diff * is->audio_st->codec->sample_rate) * n); + wanted_size = samples_size + ((int)(diff * is->sdl_sample_rate) * n); nb_samples = samples_size / n; min_size = ((nb_samples * (100 - SAMPLE_CORRECTION_PERCENT_MAX)) / 100) * n; @@ -1851,7 +1857,7 @@ static int synchronize_audio(VideoState *is, short *samples, samples_size = wanted_size; } } - av_dlog(NULL, "diff=%f adiff=%f sample_diff=%d apts=%0.3f vpts=%0.3f %f\n", + av_log(NULL, AV_LOG_TRACE, "diff=%f adiff=%f sample_diff=%d apts=%0.3f vpts=%0.3f %f\n", diff, avg_diff, samples_size - samples_size1, is->audio_clock, is->video_clock, is->audio_diff_threshold); } @@ -1883,10 +1889,9 @@ static int audio_decode_frame(VideoState *is, double *pts_ptr) int resample_changed, audio_resample; if (!is->frame) { - if (!(is->frame = avcodec_alloc_frame())) + if (!(is->frame = av_frame_alloc())) return AVERROR(ENOMEM); - } else - avcodec_get_frame_defaults(is->frame); + } if (flush_complete) break; @@ -1909,13 +1914,15 @@ static int audio_decode_frame(VideoState *is, double *pts_ptr) } data_size = av_samples_get_buffer_size(NULL, dec->channels, is->frame->nb_samples, - dec->sample_fmt, 1); + is->frame->format, 1); - audio_resample = dec->sample_fmt != is->sdl_sample_fmt || - dec->channel_layout != is->sdl_channel_layout; + audio_resample = is->frame->format != is->sdl_sample_fmt || + is->frame->channel_layout != is->sdl_channel_layout || + is->frame->sample_rate != is->sdl_sample_rate; - resample_changed = dec->sample_fmt != is->resample_sample_fmt || - dec->channel_layout != is->resample_channel_layout; + resample_changed = is->frame->format != is->resample_sample_fmt || + is->frame->channel_layout != is->resample_channel_layout || + is->frame->sample_rate != is->resample_sample_rate; if ((!is->avr && audio_resample) || resample_changed) { int ret; @@ -1929,20 +1936,21 @@ static int audio_decode_frame(VideoState *is, double *pts_ptr) } } if (audio_resample) { - av_opt_set_int(is->avr, "in_channel_layout", dec->channel_layout, 0); - av_opt_set_int(is->avr, "in_sample_fmt", dec->sample_fmt, 0); - av_opt_set_int(is->avr, "in_sample_rate", dec->sample_rate, 0); - av_opt_set_int(is->avr, "out_channel_layout", is->sdl_channel_layout, 0); - av_opt_set_int(is->avr, "out_sample_fmt", is->sdl_sample_fmt, 0); - av_opt_set_int(is->avr, "out_sample_rate", dec->sample_rate, 0); + av_opt_set_int(is->avr, "in_channel_layout", is->frame->channel_layout, 0); + av_opt_set_int(is->avr, "in_sample_fmt", is->frame->format, 0); + av_opt_set_int(is->avr, "in_sample_rate", is->frame->sample_rate, 0); + av_opt_set_int(is->avr, "out_channel_layout", is->sdl_channel_layout, 0); + av_opt_set_int(is->avr, "out_sample_fmt", is->sdl_sample_fmt, 0); + av_opt_set_int(is->avr, "out_sample_rate", is->sdl_sample_rate, 0); if ((ret = avresample_open(is->avr)) < 0) { fprintf(stderr, "error initializing libavresample\n"); break; } } - is->resample_sample_fmt = dec->sample_fmt; - is->resample_channel_layout = dec->channel_layout; + is->resample_sample_fmt = is->frame->format; + is->resample_channel_layout = is->frame->channel_layout; + is->resample_sample_rate = is->frame->sample_rate; } if (audio_resample) { @@ -1961,9 +1969,9 @@ static int audio_decode_frame(VideoState *is, double *pts_ptr) is->audio_buf1 = tmp_out; out_samples = avresample_convert(is->avr, - (void **)&is->audio_buf1, + &is->audio_buf1, out_linesize, nb_samples, - (void **)is->frame->data, + is->frame->data, is->frame->linesize[0], is->frame->nb_samples); if (out_samples < 0) { @@ -1981,7 +1989,7 @@ static int audio_decode_frame(VideoState *is, double *pts_ptr) *pts_ptr = pts; n = is->sdl_channels * av_get_bytes_per_sample(is->sdl_sample_fmt); is->audio_clock += (double)data_size / - (double)(n * dec->sample_rate); + (double)(n * is->sdl_sample_rate); #ifdef DEBUG { static double last_clock; @@ -2028,7 +2036,7 @@ static void sdl_audio_callback(void *opaque, Uint8 *stream, int len) int audio_size, len1; double pts; - audio_callback_time = av_gettime(); + audio_callback_time = av_gettime_relative(); while (len > 0) { if (is->audio_buf_index >= is->audio_buf_size) { @@ -2065,6 +2073,7 @@ static int stream_component_open(VideoState *is, int stream_index) SDL_AudioSpec wanted_spec, spec; AVDictionary *opts; AVDictionaryEntry *t = NULL; + int ret = 0; if (stream_index < 0 || stream_index >= ic->nb_streams) return -1; @@ -2073,8 +2082,6 @@ static int stream_component_open(VideoState *is, int stream_index) opts = filter_codec_opts(codec_opts, avctx->codec_id, ic, ic->streams[stream_index], NULL); codec = avcodec_find_decoder(avctx->codec_id); - avctx->debug_mv = debug_mv; - avctx->debug = debug; avctx->workaround_bugs = workaround_bugs; avctx->idct_algo = idct; avctx->skip_frame = skip_frame; @@ -2086,24 +2093,28 @@ static int stream_component_open(VideoState *is, int stream_index) if (!av_dict_get(opts, "threads", NULL, 0)) av_dict_set(&opts, "threads", "auto", 0); + if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) + av_dict_set(&opts, "refcounted_frames", "1", 0); if (!codec || - avcodec_open2(avctx, codec, &opts) < 0) - return -1; + (ret = avcodec_open2(avctx, codec, &opts)) < 0) { + goto fail; + } if ((t = av_dict_get(opts, "", NULL, AV_DICT_IGNORE_SUFFIX))) { av_log(NULL, AV_LOG_ERROR, "Option %s not found.\n", t->key); - return AVERROR_OPTION_NOT_FOUND; + ret = AVERROR_OPTION_NOT_FOUND; + goto fail; } /* prepare audio output */ if (avctx->codec_type == AVMEDIA_TYPE_AUDIO) { - wanted_spec.freq = avctx->sample_rate; - wanted_spec.format = AUDIO_S16SYS; + is->sdl_sample_rate = avctx->sample_rate; if (!avctx->channel_layout) avctx->channel_layout = av_get_default_channel_layout(avctx->channels); if (!avctx->channel_layout) { fprintf(stderr, "unable to guess channel layout\n"); - return -1; + ret = AVERROR_INVALIDDATA; + goto fail; } if (avctx->channels == 1) is->sdl_channel_layout = AV_CH_LAYOUT_MONO; @@ -2111,6 +2122,8 @@ static int stream_component_open(VideoState *is, int stream_index) is->sdl_channel_layout = AV_CH_LAYOUT_STEREO; is->sdl_channels = av_get_channel_layout_nb_channels(is->sdl_channel_layout); + wanted_spec.format = AUDIO_S16SYS; + wanted_spec.freq = is->sdl_sample_rate; wanted_spec.channels = is->sdl_channels; wanted_spec.silence = 0; wanted_spec.samples = SDL_AUDIO_BUFFER_SIZE; @@ -2118,12 +2131,14 @@ static int stream_component_open(VideoState *is, int stream_index) wanted_spec.userdata = is; if (SDL_OpenAudio(&wanted_spec, &spec) < 0) { fprintf(stderr, "SDL_OpenAudio: %s\n", SDL_GetError()); - return -1; + ret = AVERROR_UNKNOWN; + goto fail; } is->audio_hw_buf_size = spec.size; is->sdl_sample_fmt = AV_SAMPLE_FMT_S16; is->resample_sample_fmt = is->sdl_sample_fmt; - is->resample_channel_layout = is->sdl_channel_layout; + is->resample_channel_layout = avctx->channel_layout; + is->resample_sample_rate = avctx->sample_rate; } ic->streams[stream_index]->discard = AVDISCARD_DEFAULT; @@ -2162,7 +2177,11 @@ static int stream_component_open(VideoState *is, int stream_index) default: break; } - return 0; + +fail: + av_dict_free(&opts); + + return ret; } static void stream_component_close(VideoState *is, int stream_index) @@ -2186,7 +2205,7 @@ static void stream_component_close(VideoState *is, int stream_index) avresample_free(&is->avr); av_freep(&is->audio_buf1); is->audio_buf = NULL; - avcodec_free_frame(&is->frame); + av_frame_free(&is->frame); if (is->rdft) { av_rdft_end(is->rdft); @@ -2229,9 +2248,6 @@ static void stream_component_close(VideoState *is, int stream_index) ic->streams[stream_index]->discard = AVDISCARD_ALL; avcodec_close(avctx); -#if CONFIG_AVFILTER - free_buffer_pool(&is->buffer_pool); -#endif switch (avctx->codec_type) { case AVMEDIA_TYPE_AUDIO: is->audio_st = NULL; @@ -2281,6 +2297,11 @@ static int decode_thread(void *arg) global_video_state = is; ic = avformat_alloc_context(); + if (!ic) { + av_log(NULL, AV_LOG_FATAL, "Could not allocate context.\n"); + ret = AVERROR(ENOMEM); + goto fail; + } ic->interrupt_callback.callback = decode_interrupt_cb; err = avformat_open_input(&ic, is->filename, is->iformat, &format_opts); if (err < 0) { @@ -2302,14 +2323,16 @@ static int decode_thread(void *arg) orig_nb_streams = ic->nb_streams; err = avformat_find_stream_info(ic, opts); + + for (i = 0; i < orig_nb_streams; i++) + av_dict_free(&opts[i]); + av_freep(&opts); + if (err < 0) { fprintf(stderr, "%s: could not find codec parameters\n", is->filename); ret = -1; goto fail; } - for (i = 0; i < orig_nb_streams; i++) - av_dict_free(&opts[i]); - av_freep(&opts); if (ic->pb) ic->pb->eof_reached = 0; // FIXME hack, avplay maybe should not use url_feof() to test for the end @@ -2457,7 +2480,7 @@ static int decode_thread(void *arg) if (is->audioq.size + is->videoq.size + is->subtitleq.size == 0) { if (loop != 1 && (!loop || --loop)) { stream_seek(cur_stream, start_time != AV_NOPTS_VALUE ? start_time : 0, 0, 0); - } else if (autoexit) { + } else if (!noautoexit) { ret = AVERROR_EOF; goto fail; } @@ -2639,6 +2662,33 @@ static void toggle_audio_display(void) } } +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); +} + /* handle an event sent by the GUI */ static void event_loop(void) { @@ -2684,6 +2734,12 @@ static void event_loop(void) case SDLK_w: toggle_audio_display(); break; + case SDLK_PAGEUP: + seek_chapter(cur_stream, 1); + break; + case SDLK_PAGEDOWN: + seek_chapter(cur_stream, -1); + break; case SDLK_LEFT: incr = -10.0; goto do_seek; @@ -2849,19 +2905,6 @@ static int opt_duration(void *optctx, const char *opt, const char *arg) return 0; } -static int opt_debug(void *optctx, const char *opt, const char *arg) -{ - av_log_set_level(99); - debug = parse_number_or_die(opt, arg, OPT_INT64, 0, INT_MAX); - return 0; -} - -static int opt_vismv(void *optctx, const char *opt, const char *arg) -{ - debug_mv = parse_number_or_die(opt, arg, OPT_INT64, INT_MIN, INT_MAX); - return 0; -} - static const OptionDef options[] = { #include "cmdutils_common_opts.h" { "x", HAS_ARG, { .func_arg = opt_width }, "force displayed width", "width" }, @@ -2880,9 +2923,7 @@ static const OptionDef options[] = { { "f", HAS_ARG, { .func_arg = opt_format }, "force format", "fmt" }, { "pix_fmt", HAS_ARG | OPT_EXPERT | OPT_VIDEO, { .func_arg = opt_frame_pix_fmt }, "set pixel format", "format" }, { "stats", OPT_BOOL | OPT_EXPERT, { &show_status }, "show status", "" }, - { "debug", HAS_ARG | OPT_EXPERT, { .func_arg = opt_debug }, "print specific debug info", "" }, { "bug", OPT_INT | HAS_ARG | OPT_EXPERT, { &workaround_bugs }, "workaround bugs", "" }, - { "vismv", HAS_ARG | OPT_EXPERT, { .func_arg = opt_vismv }, "visualize motion vectors", "" }, { "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", ""}, @@ -2892,7 +2933,7 @@ static const OptionDef options[] = { { "idct", OPT_INT | HAS_ARG | OPT_EXPERT, { &idct }, "set idct algo", "algo" }, { "ec", OPT_INT | HAS_ARG | OPT_EXPERT, { &error_concealment }, "set error concealment options", "bit_mask" }, { "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", "" }, + { "noautoexit", OPT_BOOL | OPT_EXPERT, { &noautoexit }, "Do not exit at the end of playback", "" }, { "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" }, @@ -2905,6 +2946,7 @@ static const OptionDef options[] = { { "rdftspeed", OPT_INT | HAS_ARG| OPT_AUDIO | OPT_EXPERT, { &rdftspeed }, "rdft speed", "msecs" }, { "default", HAS_ARG | OPT_AUDIO | OPT_VIDEO | OPT_EXPERT, { opt_default }, "generic catch all option", "" }, { "i", 0, { NULL }, "avconv compatibility dummy option", ""}, + { "autorotate", OPT_BOOL, { &autorotate }, "automatically rotate video", "" }, { NULL, }, }; @@ -2999,11 +3041,9 @@ int main(int argc, char **argv) } if (!display_disable) { -#if HAVE_SDL_VIDEO_SIZE const SDL_VideoInfo *vi = SDL_GetVideoInfo(); fs_screen_width = vi->current_w; fs_screen_height = vi->current_h; -#endif } SDL_EventState(SDL_ACTIVEEVENT, SDL_IGNORE); @@ -3011,7 +3051,7 @@ int main(int argc, char **argv) SDL_EventState(SDL_USEREVENT, SDL_IGNORE); av_init_packet(&flush_pkt); - flush_pkt.data = "FLUSH"; + flush_pkt.data = (uint8_t *)&flush_pkt; cur_stream = stream_open(input_filename, file_iformat);