X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;ds=sidebyside;f=avplay.c;h=56ec7316e5c7e71bc06074589da64ae55971d1ed;hb=ce70f28a1732c74a9cd7fec2d56178750bd6e457;hp=96e0cf2d9efae6c2845bda070c03fcc5b243f9bd;hpb=8f8bc92365a943e96cc08b5369408c20f35193c7;p=ffmpeg diff --git a/avplay.c b/avplay.c index 96e0cf2d9ef..56ec7316e5c 100644 --- a/avplay.c +++ b/avplay.c @@ -27,6 +27,7 @@ #include "libavutil/avstring.h" #include "libavutil/colorspace.h" +#include "libavutil/display.h" #include "libavutil/mathematics.h" #include "libavutil/pixdesc.h" #include "libavutil/imgutils.h" @@ -101,7 +102,7 @@ typedef struct PacketQueue { typedef struct VideoPicture { double pts; // presentation timestamp for this picture - double target_clock; // av_gettime() time at which this should be displayed ideally + 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 */ @@ -197,7 +198,7 @@ typedef struct VideoState { 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 + 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; @@ -254,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; @@ -265,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; @@ -297,7 +299,7 @@ static void packet_queue_flush(PacketQueue *q) SDL_LockMutex(q->mutex); for (pkt = q->first_pkt; pkt != NULL; pkt = pkt1) { pkt1 = pkt->next; - av_free_packet(&pkt->pkt); + av_packet_unref(&pkt->pkt); av_freep(&pkt); } q->last_pkt = NULL; @@ -318,10 +320,6 @@ static int packet_queue_put(PacketQueue *q, AVPacket *pkt) { AVPacketList *pkt1; - /* duplicate the packet */ - if (pkt != &flush_pkt && av_dup_packet(pkt) < 0) - return -1; - pkt1 = av_malloc(sizeof(AVPacketList)); if (!pkt1) return -1; @@ -433,7 +431,8 @@ static inline void fill_rectangle(SDL_Surface *screen, #define BPP 1 -static void blend_subrect(AVPicture *dst, const AVSubtitleRect *rect, int imgw, int imgh) +static void blend_subrect(uint8_t *dst[4], uint16_t dst_linesize[4], + const AVSubtitleRect *rect, int imgw, int imgh) { int wrap, wrap3, width2, skip2; int y, u, v, a, u1, v1, a1, w, h; @@ -446,16 +445,17 @@ static void blend_subrect(AVPicture *dst, const AVSubtitleRect *rect, int imgw, dsth = av_clip(rect->h, 0, imgh); dstx = av_clip(rect->x, 0, imgw - dstw); dsty = av_clip(rect->y, 0, imgh - dsth); - lum = dst->data[0] + dsty * dst->linesize[0]; - cb = dst->data[1] + (dsty >> 1) * dst->linesize[1]; - cr = dst->data[2] + (dsty >> 1) * dst->linesize[2]; + /* sdl has U and V inverted */ + lum = dst[0] + dsty * dst_linesize[0]; + cb = dst[2] + (dsty >> 1) * dst_linesize[2]; + cr = dst[1] + (dsty >> 1) * dst_linesize[1]; width2 = ((dstw + 1) >> 1) + (dstx & ~dstw & 1); skip2 = dstx >> 1; - wrap = dst->linesize[0]; - wrap3 = rect->pict.linesize[0]; - p = rect->pict.data[0]; - pal = (const uint32_t *)rect->pict.data[1]; /* Now in YCrCb! */ + wrap = dst_linesize[0]; + wrap3 = rect->linesize[0]; + p = rect->data[0]; + pal = (const uint32_t *)rect->data[1]; /* Now in YCrCb! */ if (dsty & 1) { lum += dstx; @@ -501,8 +501,8 @@ static void blend_subrect(AVPicture *dst, const AVSubtitleRect *rect, int imgw, } p += wrap3 - dstw * BPP; lum += wrap - dstw - dstx; - cb += dst->linesize[1] - width2 - skip2; - cr += dst->linesize[2] - width2 - skip2; + cb += dst_linesize[2] - width2 - skip2; + cr += dst_linesize[1] - width2 - skip2; } for (h = dsth - (dsty & 1); h >= 2; h -= 2) { lum += dstx; @@ -586,8 +586,8 @@ static void blend_subrect(AVPicture *dst, const AVSubtitleRect *rect, int imgw, } p += wrap3 + (wrap3 - dstw * BPP); lum += wrap + (wrap - dstw - dstx); - cb += dst->linesize[1] - width2 - skip2; - cr += dst->linesize[2] - width2 - skip2; + cb += dst_linesize[2] - width2 - skip2; + cr += dst_linesize[1] - width2 - skip2; } /* handle odd height */ if (h) { @@ -642,7 +642,6 @@ static void video_image_display(VideoState *is) { VideoPicture *vp; SubPicture *sp; - AVPicture pict; float aspect_ratio; int width, height, x, y; SDL_Rect rect; @@ -679,17 +678,9 @@ static void video_image_display(VideoState *is) { SDL_LockYUVOverlay (vp->bmp); - pict.data[0] = vp->bmp->pixels[0]; - pict.data[1] = vp->bmp->pixels[2]; - pict.data[2] = vp->bmp->pixels[1]; - - pict.linesize[0] = vp->bmp->pitches[0]; - pict.linesize[1] = vp->bmp->pitches[2]; - pict.linesize[2] = vp->bmp->pitches[1]; - for (i = 0; i < sp->sub.num_rects; i++) - blend_subrect(&pict, sp->sub.rects[i], - vp->bmp->w, vp->bmp->h); + blend_subrect(vp->bmp->pixels, vp->bmp->pitches, + sp->sub.rects[i], vp->bmp->w, vp->bmp->h); SDL_UnlockYUVOverlay (vp->bmp); } @@ -754,7 +745,7 @@ 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; + time_diff = av_gettime_relative() - audio_callback_time; delay -= (time_diff * s->sdl_sample_rate) / 1000000; } @@ -972,7 +963,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; } } @@ -980,7 +971,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); } @@ -1022,18 +1013,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; @@ -1065,7 +1056,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; @@ -1084,7 +1075,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]; @@ -1190,7 +1181,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; @@ -1301,9 +1292,7 @@ static void alloc_picture(void *opaque) static int queue_picture(VideoState *is, AVFrame *src_frame, double pts, int64_t pos) { VideoPicture *vp; -#if CONFIG_AVFILTER - AVPicture pict_src; -#else +#if !CONFIG_AVFILTER int dst_pix_fmt = AV_PIX_FMT_YUV420P; #endif /* wait until we have space to put a new picture */ @@ -1323,6 +1312,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 @@ -1356,42 +1347,35 @@ 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 } }; + uint8_t *data[4]; + int linesize[4]; /* get a pointer on the bitmap */ SDL_LockYUVOverlay (vp->bmp); - pict.data[0] = vp->bmp->pixels[0]; - pict.data[1] = vp->bmp->pixels[2]; - pict.data[2] = vp->bmp->pixels[1]; + data[0] = vp->bmp->pixels[0]; + data[1] = vp->bmp->pixels[2]; + data[2] = vp->bmp->pixels[1]; - pict.linesize[0] = vp->bmp->pitches[0]; - pict.linesize[1] = vp->bmp->pitches[2]; - pict.linesize[2] = vp->bmp->pitches[1]; + linesize[0] = vp->bmp->pitches[0]; + linesize[1] = vp->bmp->pitches[2]; + linesize[2] = vp->bmp->pitches[1]; #if CONFIG_AVFILTER - pict_src.data[0] = src_frame->data[0]; - pict_src.data[1] = src_frame->data[1]; - pict_src.data[2] = src_frame->data[2]; - - pict_src.linesize[0] = src_frame->linesize[0]; - pict_src.linesize[1] = src_frame->linesize[1]; - pict_src.linesize[2] = src_frame->linesize[2]; - // FIXME use direct rendering - av_picture_copy(&pict, &pict_src, - vp->pix_fmt, vp->width, vp->height); + av_image_copy(data, linesize, src_frame->data, src_frame->linesize, + vp->pix_fmt, vp->width, vp->height); #else 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); } sws_scale(is->img_convert_ctx, src_frame->data, src_frame->linesize, - 0, vp->height, pict.data, pict.linesize); + 0, vp->height, data, linesize); #endif /* update the bitmap content */ SDL_UnlockYUVOverlay(vp->bmp); @@ -1462,7 +1446,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; @@ -1502,7 +1486,7 @@ 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=%"PRId64, sws_flags); @@ -1524,13 +1508,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(); @@ -1542,14 +1556,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; } @@ -1578,6 +1592,10 @@ static int video_thread(void *arg) AVFilterContext *filt_out = NULL, *filt_in = NULL; 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; @@ -1585,6 +1603,13 @@ 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 AVRational tb; @@ -1592,7 +1617,7 @@ static int video_thread(void *arg) while (is->paused && !is->videoq.abort_request) SDL_Delay(10); - av_free_packet(&pkt); + av_packet_unref(&pkt); ret = get_video_frame(is, frame, &pts_int, &pkt); if (ret < 0) @@ -1604,7 +1629,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(); @@ -1633,7 +1658,7 @@ static int video_thread(void *arg) 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); @@ -1659,7 +1684,7 @@ static int video_thread(void *arg) av_freep(&vfilters); avfilter_graph_free(&graph); #endif - av_free_packet(&pkt); + av_packet_unref(&pkt); av_frame_free(&frame); return 0; } @@ -1713,11 +1738,11 @@ static int subtitle_thread(void *arg) { for (j = 0; j < sp->sub.rects[i]->nb_colors; j++) { - RGBA_IN(r, g, b, a, (uint32_t*)sp->sub.rects[i]->pict.data[1] + j); + RGBA_IN(r, g, b, a, (uint32_t *)sp->sub.rects[i]->data[1] + j); y = RGB_TO_Y_CCIR(r, g, b); u = RGB_TO_U_CCIR(r, g, b, 0); v = RGB_TO_V_CCIR(r, g, b, 0); - YUVA_OUT((uint32_t*)sp->sub.rects[i]->pict.data[1] + j, y, u, v, a); + YUVA_OUT((uint32_t *)sp->sub.rects[i]->data[1] + j, y, u, v, a); } } @@ -1728,7 +1753,7 @@ static int subtitle_thread(void *arg) is->subpq_size++; SDL_UnlockMutex(is->subpq_mutex); } - av_free_packet(pkt); + av_packet_unref(pkt); } return 0; } @@ -1812,7 +1837,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); } @@ -1846,8 +1871,7 @@ static int audio_decode_frame(VideoState *is, double *pts_ptr) if (!is->frame) { if (!(is->frame = av_frame_alloc())) return AVERROR(ENOMEM); - } else - avcodec_get_frame_defaults(is->frame); + } if (flush_complete) break; @@ -1864,7 +1888,7 @@ static int audio_decode_frame(VideoState *is, double *pts_ptr) if (!got_frame) { /* stop sending empty packets if the decoder is finished */ - if (!pkt_temp->data && dec->codec->capabilities & CODEC_CAP_DELAY) + if (!pkt_temp->data && (dec->codec->capabilities & AV_CODEC_CAP_DELAY)) flush_complete = 1; continue; } @@ -1960,7 +1984,7 @@ static int audio_decode_frame(VideoState *is, double *pts_ptr) /* free the current packet */ if (pkt->data) - av_free_packet(pkt); + av_packet_unref(pkt); memset(pkt_temp, 0, sizeof(*pkt_temp)); if (is->paused || is->audioq.abort_request) { @@ -1992,7 +2016,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) { @@ -2029,6 +2053,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; @@ -2044,18 +2069,21 @@ static int stream_component_open(VideoState *is, int stream_index) avctx->skip_loop_filter = skip_loop_filter; avctx->error_concealment = error_concealment; - if (fast) avctx->flags2 |= CODEC_FLAG2_FAST; + if (fast) + avctx->flags2 |= AV_CODEC_FLAG2_FAST; 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 */ @@ -2066,7 +2094,8 @@ static int stream_component_open(VideoState *is, int stream_index) 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; @@ -2083,7 +2112,8 @@ 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; @@ -2128,7 +2158,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) @@ -2147,12 +2181,12 @@ static void stream_component_close(VideoState *is, int stream_index) SDL_CloseAudio(); packet_queue_end(&is->audioq); - av_free_packet(&is->audio_pkt); + av_packet_unref(&is->audio_pkt); if (is->avr) 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); @@ -2244,6 +2278,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) { @@ -2265,14 +2304,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 @@ -2409,7 +2450,7 @@ static int decode_thread(void *arg) packet_queue_put(&is->videoq, pkt); } if (is->audio_stream >= 0 && - is->audio_st->codec->codec->capabilities & CODEC_CAP_DELAY) { + (is->audio_st->codec->codec->capabilities & AV_CODEC_CAP_DELAY)) { av_init_packet(pkt); pkt->data = NULL; pkt->size = 0; @@ -2420,7 +2461,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; } @@ -2449,7 +2490,7 @@ static int decode_thread(void *arg) } else if (pkt->stream_index == is->subtitle_stream && pkt_in_play_range) { packet_queue_put(&is->subtitleq, pkt); } else { - av_free_packet(pkt); + av_packet_unref(pkt); } } /* wait until the end */ @@ -2602,6 +2643,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) { @@ -2647,6 +2715,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; @@ -2840,7 +2914,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" }, @@ -2853,6 +2927,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, }, };