X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=avplay.c;h=e5ee9dbbef435e1752835d7cd44ac1080cd5b26a;hb=3cba1ad76d362c994fa98fb686e04e20826fb579;hp=b70ee54c7b904b4073fb7d8f2c2c3be506bcde01;hpb=b36bc81ccaa2fc85dc4bae7dc546c71e8833573d;p=ffmpeg diff --git a/avplay.c b/avplay.c index b70ee54c7b9..e5ee9dbbef4 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" @@ -36,16 +37,13 @@ #include "libavutil/time.h" #include "libavformat/avformat.h" #include "libavdevice/avdevice.h" -#include "libswscale/swscale.h" #include "libavresample/avresample.h" #include "libavutil/opt.h" #include "libavcodec/avfft.h" -#if CONFIG_AVFILTER -# include "libavfilter/avfilter.h" -# include "libavfilter/buffersink.h" -# include "libavfilter/buffersrc.h" -#endif +#include "libavfilter/avfilter.h" +#include "libavfilter/buffersink.h" +#include "libavfilter/buffersrc.h" #include "cmdutils.h" @@ -101,7 +99,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 */ @@ -123,7 +121,7 @@ enum { AV_SYNC_EXTERNAL_CLOCK, /* synchronize to an external clock */ }; -typedef struct VideoState { +typedef struct PlayerState { SDL_Thread *parse_tid; SDL_Thread *video_tid; SDL_Thread *refresh_tid; @@ -151,6 +149,7 @@ typedef struct VideoState { double audio_diff_threshold; int audio_diff_avg_count; AVStream *audio_st; + AVCodecContext *audio_dec; PacketQueue audioq; int audio_hw_buf_size; uint8_t silence_buf[SDL_AUDIO_BUFFER_SIZE]; @@ -183,6 +182,7 @@ typedef struct VideoState { int subtitle_stream; int subtitle_stream_changed; AVStream *subtitle_st; + AVCodecContext *subtitle_dec; PacketQueue subtitleq; SubPicture subpq[SUBPICTURE_QUEUE_SIZE]; int subpq_size, subpq_rindex, subpq_windex; @@ -195,17 +195,15 @@ typedef struct VideoState { double video_clock; // pts of last decoded frame / predicted pts of next decoded frame int video_stream; AVStream *video_st; + AVCodecContext *video_dec; 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; SDL_mutex *pictq_mutex; SDL_cond *pictq_cond; -#if !CONFIG_AVFILTER - struct SwsContext *img_convert_ctx; -#endif // QETimer *video_timer; char filename[1024]; @@ -213,15 +211,16 @@ 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 -#endif float skip_frames; float skip_frames_index; int refresh; -} VideoState; + + SpecifierOpt *codec_names; + int nb_codec_names; +} PlayerState; /* options specified by the user */ static AVInputFormat *file_iformat; @@ -254,7 +253,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; @@ -262,13 +261,13 @@ static int framedrop = 1; static int infinite_buffer = 0; static int rdftspeed = 20; -#if CONFIG_AVFILTER static char *vfilters = NULL; -#endif +static int autorotate = 1; /* current context */ static int is_full_screen; -static VideoState *cur_stream; +static PlayerState player_state; +static PlayerState *player = &player_state; static int64_t audio_callback_time; static AVPacket flush_pkt; @@ -297,7 +296,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 +317,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 +428,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 +442,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 +498,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 +583,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) { @@ -638,11 +635,10 @@ static void free_subpicture(SubPicture *sp) avsubtitle_free(&sp->sub); } -static void video_image_display(VideoState *is) +static void video_image_display(PlayerState *is) { VideoPicture *vp; SubPicture *sp; - AVPicture pict; float aspect_ratio; int width, height, x, y; SDL_Rect rect; @@ -650,21 +646,10 @@ static void video_image_display(VideoState *is) vp = &is->pictq[is->pictq_rindex]; if (vp->bmp) { -#if CONFIG_AVFILTER if (!vp->sar.num) aspect_ratio = 0; else aspect_ratio = av_q2d(vp->sar); -#else - - /* XXX: use variable in the frame */ - if (is->video_st->sample_aspect_ratio.num) - aspect_ratio = av_q2d(is->video_st->sample_aspect_ratio); - else if (is->video_st->codec->sample_aspect_ratio.num) - aspect_ratio = av_q2d(is->video_st->codec->sample_aspect_ratio); - else - aspect_ratio = 0; -#endif if (aspect_ratio <= 0.0) aspect_ratio = 1.0; aspect_ratio *= (float)vp->width / (float)vp->height; @@ -679,17 +664,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); } @@ -717,7 +694,7 @@ static void video_image_display(VideoState *is) /* get the current audio output buffer size, in samples. With SDL, we cannot have a precise information */ -static int audio_write_get_buf_size(VideoState *is) +static int audio_write_get_buf_size(PlayerState *is) { return is->audio_buf_size - is->audio_buf_index; } @@ -731,7 +708,7 @@ static inline int compute_mod(int a, int b) return a + b; } -static void video_audio_display(VideoState *s) +static void video_audio_display(PlayerState *s) { int i, i_start, x, y1, y, ys, delay, n, nb_display_channels; int ch, channels, h, h2, bgcolor, fgcolor; @@ -754,7 +731,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; } @@ -871,7 +848,7 @@ static void video_audio_display(VideoState *s) } } -static int video_open(VideoState *is) +static int video_open(PlayerState *is) { int flags = SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL; int w,h; @@ -885,15 +862,9 @@ static int video_open(VideoState *is) } else if (!is_full_screen && screen_width) { w = screen_width; h = screen_height; -#if CONFIG_AVFILTER } else if (is->out_video_filter && is->out_video_filter->inputs[0]) { w = is->out_video_filter->inputs[0]->w; h = is->out_video_filter->inputs[0]->h; -#else - } else if (is->video_st && is->video_st->codec->width) { - w = is->video_st->codec->width; - h = is->video_st->codec->height; -#endif } else { w = 640; h = 480; @@ -923,10 +894,10 @@ static int video_open(VideoState *is) } /* display the current picture, if any */ -static void video_display(VideoState *is) +static void video_display(PlayerState *is) { if (!screen) - video_open(cur_stream); + video_open(player); if (is->audio_st && is->show_audio) video_audio_display(is); else if (is->video_st) @@ -935,7 +906,7 @@ static void video_display(VideoState *is) static int refresh_thread(void *opaque) { - VideoState *is= opaque; + PlayerState *is= opaque; while (!is->abort_request) { SDL_Event event; event.type = FF_REFRESH_EVENT; @@ -950,7 +921,7 @@ static int refresh_thread(void *opaque) } /* get the current audio clock value */ -static double get_audio_clock(VideoState *is) +static double get_audio_clock(PlayerState *is) { double pts; int hw_buf_size, bytes_per_sec; @@ -967,25 +938,25 @@ static double get_audio_clock(VideoState *is) } /* get the current video clock value */ -static double get_video_clock(VideoState *is) +static double get_video_clock(PlayerState *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; } } /* get the current external clock value */ -static double get_external_clock(VideoState *is) +static double get_external_clock(PlayerState *is) { int64_t ti; - ti = av_gettime(); + ti = av_gettime_relative(); return is->external_clock + ((ti - is->external_clock_time) * 1e-6); } /* get the current master clock value */ -static double get_master_clock(VideoState *is) +static double get_master_clock(PlayerState *is) { double val; @@ -1006,7 +977,7 @@ static double get_master_clock(VideoState *is) } /* seek in the stream */ -static void stream_seek(VideoState *is, int64_t pos, int64_t rel, int seek_by_bytes) +static void stream_seek(PlayerState *is, int64_t pos, int64_t rel, int seek_by_bytes) { if (!is->seek_req) { is->seek_pos = pos; @@ -1019,21 +990,21 @@ static void stream_seek(VideoState *is, int64_t pos, int64_t rel, int seek_by_by } /* pause or resume the video */ -static void stream_pause(VideoState *is) +static void stream_pause(PlayerState *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) +static double compute_target_time(double frame_current_pts, PlayerState *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 +1036,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; @@ -1074,7 +1045,7 @@ static double compute_target_time(double frame_current_pts, VideoState *is) /* called to display each frame */ static void video_refresh_timer(void *opaque) { - VideoState *is = opaque; + PlayerState *is = opaque; VideoPicture *vp; SubPicture *sp, *sp2; @@ -1084,7 +1055,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 +1161,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; @@ -1213,7 +1184,7 @@ retry: } } -static void stream_close(VideoState *is) +static void player_close(PlayerState *is) { VideoPicture *vp; int i; @@ -1234,18 +1205,13 @@ static void stream_close(VideoState *is) SDL_DestroyCond(is->pictq_cond); SDL_DestroyMutex(is->subpq_mutex); SDL_DestroyCond(is->subpq_cond); -#if !CONFIG_AVFILTER - if (is->img_convert_ctx) - sws_freeContext(is->img_convert_ctx); -#endif - av_free(is); } static void do_exit(void) { - if (cur_stream) { - stream_close(cur_stream); - cur_stream = NULL; + if (player) { + player_close(player); + player = NULL; } uninit_opts(); avformat_network_deinit(); @@ -1260,7 +1226,7 @@ static void do_exit(void) potential locking problems */ static void alloc_picture(void *opaque) { - VideoState *is = opaque; + PlayerState *is = opaque; VideoPicture *vp; vp = &is->pictq[is->pictq_windex]; @@ -1268,15 +1234,9 @@ static void alloc_picture(void *opaque) if (vp->bmp) SDL_FreeYUVOverlay(vp->bmp); -#if CONFIG_AVFILTER 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; -#else - vp->width = is->video_st->codec->width; - vp->height = is->video_st->codec->height; - vp->pix_fmt = is->video_st->codec->pix_fmt; -#endif vp->bmp = SDL_CreateYUVOverlay(vp->width, vp->height, SDL_YV12_OVERLAY, @@ -1298,14 +1258,10 @@ static void alloc_picture(void *opaque) /* 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) +static int queue_picture(PlayerState *is, AVFrame *src_frame, double pts, int64_t pos) { VideoPicture *vp; -#if CONFIG_AVFILTER - AVPicture pict_src; -#else - int dst_pix_fmt = AV_PIX_FMT_YUV420P; -#endif + /* wait until we have space to put a new picture */ SDL_LockMutex(is->pictq_mutex); @@ -1323,15 +1279,12 @@ 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 vp->width != is->out_video_filter->inputs[0]->w || vp->height != is->out_video_filter->inputs[0]->h) { -#else - vp->width != is->video_st->codec->width || - vp->height != is->video_st->codec->height) { -#endif SDL_Event event; vp->allocated = 0; @@ -1356,43 +1309,24 @@ 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]; - -#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]; + linesize[0] = vp->bmp->pitches[0]; + linesize[1] = vp->bmp->pitches[2]; + linesize[2] = vp->bmp->pitches[1]; // FIXME use direct rendering - av_picture_copy(&pict, &pict_src, - 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) { - 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); -#endif + av_image_copy(data, linesize, src_frame->data, src_frame->linesize, + vp->pix_fmt, vp->width, vp->height); + /* update the bitmap content */ SDL_UnlockYUVOverlay(vp->bmp); @@ -1413,7 +1347,7 @@ static int queue_picture(VideoState *is, AVFrame *src_frame, double pts, int64_t /* 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) +static int output_picture2(PlayerState *is, AVFrame *src_frame, double pts1, int64_t pos) { double frame_delay, pts; int ret; @@ -1427,8 +1361,8 @@ static int output_picture2(VideoState *is, AVFrame *src_frame, double pts1, int6 pts = is->video_clock; } /* update video clock for next frame */ - frame_delay = av_q2d(is->video_st->codec->time_base); - /* for MPEG2, the frame can be repeated, so we update the + frame_delay = av_q2d(is->video_dec->time_base); + /* For MPEG-2, the frame can be repeated, so we update the clock accordingly */ frame_delay += src_frame->repeat_pict * (frame_delay * 0.5); is->video_clock += frame_delay; @@ -1438,7 +1372,7 @@ static int output_picture2(VideoState *is, AVFrame *src_frame, double pts1, int6 return ret; } -static int get_video_frame(VideoState *is, AVFrame *frame, int64_t *pts, AVPacket *pkt) +static int get_video_frame(PlayerState *is, AVFrame *frame, int64_t *pts, AVPacket *pkt) { int got_picture, i; @@ -1446,7 +1380,7 @@ static int get_video_frame(VideoState *is, AVFrame *frame, int64_t *pts, AVPacke return -1; if (pkt->data == flush_pkt.data) { - avcodec_flush_buffers(is->video_st->codec); + avcodec_flush_buffers(is->video_dec); SDL_LockMutex(is->pictq_mutex); // Make sure there are no long delay timers (ideally we should just flush the que but thats harder) @@ -1462,19 +1396,19 @@ 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; } - avcodec_decode_video2(is->video_st->codec, frame, &got_picture, pkt); + avcodec_decode_video2(is->video_dec, frame, &got_picture, pkt); if (got_picture) { if (decoder_reorder_pts == -1) { - *pts = guess_correct_pts(&is->pts_ctx, frame->pkt_pts, frame->pkt_dts); + *pts = guess_correct_pts(&is->pts_ctx, frame->pts, frame->pkt_dts); } else if (decoder_reorder_pts) { - *pts = frame->pkt_pts; + *pts = frame->pts; } else { *pts = frame->pkt_dts; } @@ -1496,14 +1430,13 @@ static int get_video_frame(VideoState *is, AVFrame *frame, int64_t *pts, AVPacke return 0; } -#if CONFIG_AVFILTER -static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const char *vfilters) +static int configure_video_filters(AVFilterGraph *graph, PlayerState *is, const char *vfilters) { char sws_flags_str[128]; char buffersrc_args[256]; int ret; - AVFilterContext *filt_src = NULL, *filt_out = NULL, *filt_format; - AVCodecContext *codec = is->video_st->codec; + AVFilterContext *filt_src = NULL, *filt_out = NULL, *last_filter; + AVCodecContext *codec = is->video_dec; snprintf(sws_flags_str, sizeof(sws_flags_str), "flags=%"PRId64, sws_flags); graph->scale_sws_opts = av_strdup(sws_flags_str); @@ -1524,13 +1457,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 +1505,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; } @@ -1562,37 +1525,40 @@ static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const c return ret; } -#endif /* CONFIG_AVFILTER */ - static int video_thread(void *arg) { AVPacket pkt = { 0 }; - VideoState *is = arg; + PlayerState *is = arg; AVFrame *frame = av_frame_alloc(); int64_t pts_int; double pts; int ret; -#if CONFIG_AVFILTER AVFilterGraph *graph = avfilter_graph_alloc(); AVFilterContext *filt_out = NULL, *filt_in = NULL; - int last_w = is->video_st->codec->width; - int last_h = is->video_st->codec->height; + int last_w = is->video_dec->width; + int last_h = is->video_dec->height; + if (!graph) { + av_frame_free(&frame); + return AVERROR(ENOMEM); + } if ((ret = configure_video_filters(graph, is, vfilters)) < 0) goto the_end; filt_in = is->in_video_filter; filt_out = is->out_video_filter; -#endif + + if (!frame) { + avfilter_graph_free(&graph); + return AVERROR(ENOMEM); + } for (;;) { -#if CONFIG_AVFILTER AVRational tb; -#endif 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) @@ -1601,19 +1567,18 @@ static int video_thread(void *arg) if (!ret) continue; -#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, - is->video_st->codec->width, is->video_st->codec->height); + if ( last_w != is->video_dec->width + || last_h != is->video_dec->height) { + av_log(NULL, AV_LOG_TRACE, "Changing size %dx%d -> %dx%d\n", last_w, last_h, + is->video_dec->width, is->video_dec->height); avfilter_graph_free(&graph); graph = avfilter_graph_alloc(); if ((ret = configure_video_filters(graph, is, vfilters)) < 0) goto the_end; filt_in = is->in_video_filter; filt_out = is->out_video_filter; - last_w = is->video_st->codec->width; - last_h = is->video_st->codec->height; + last_w = is->video_dec->width; + last_h = is->video_dec->height; } frame->pts = pts_int; @@ -1633,7 +1598,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); @@ -1641,32 +1606,26 @@ static int video_thread(void *arg) pts = pts_int * av_q2d(is->video_st->time_base); ret = output_picture2(is, frame, pts, 0); } -#else - pts = pts_int * av_q2d(is->video_st->time_base); - ret = output_picture2(is, frame, pts, pkt.pos); -#endif if (ret < 0) goto the_end; if (step) - if (cur_stream) - stream_pause(cur_stream); + if (player) + stream_pause(player); } the_end: -#if CONFIG_AVFILTER av_freep(&vfilters); avfilter_graph_free(&graph); -#endif - av_free_packet(&pkt); + av_packet_unref(&pkt); av_frame_free(&frame); return 0; } static int subtitle_thread(void *arg) { - VideoState *is = arg; + PlayerState *is = arg; SubPicture *sp; AVPacket pkt1, *pkt = &pkt1; int got_subtitle; @@ -1682,7 +1641,7 @@ static int subtitle_thread(void *arg) break; if (pkt->data == flush_pkt.data) { - avcodec_flush_buffers(is->subtitle_st->codec); + avcodec_flush_buffers(is->subtitle_dec); continue; } SDL_LockMutex(is->subpq_mutex); @@ -1701,9 +1660,9 @@ static int subtitle_thread(void *arg) this packet, if any */ pts = 0; if (pkt->pts != AV_NOPTS_VALUE) - pts = av_q2d(is->subtitle_st->time_base) * pkt->pts; + pts = av_q2d(is->subtitle_dec->time_base) * pkt->pts; - avcodec_decode_subtitle2(is->subtitle_st->codec, &sp->sub, + avcodec_decode_subtitle2(is->subtitle_dec, &sp->sub, &got_subtitle, pkt); if (got_subtitle && sp->sub.format == 0) { @@ -1713,11 +1672,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,13 +1687,13 @@ static int subtitle_thread(void *arg) is->subpq_size++; SDL_UnlockMutex(is->subpq_mutex); } - av_free_packet(pkt); + av_packet_unref(pkt); } return 0; } /* copy samples for viewing in editor window */ -static void update_sample_display(VideoState *is, short *samples, int samples_size) +static void update_sample_display(PlayerState *is, short *samples, int samples_size) { int size, len; @@ -1754,7 +1713,7 @@ static void update_sample_display(VideoState *is, short *samples, int samples_si /* return the new audio buffer size (samples can be added or deleted to get better sync if video or external master clock) */ -static int synchronize_audio(VideoState *is, short *samples, +static int synchronize_audio(PlayerState *is, short *samples, int samples_size1, double pts) { int n, samples_size; @@ -1812,7 +1771,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); } @@ -1828,11 +1787,11 @@ static int synchronize_audio(VideoState *is, short *samples, } /* decode one audio frame and returns its uncompressed size */ -static int audio_decode_frame(VideoState *is, double *pts_ptr) +static int audio_decode_frame(PlayerState *is, double *pts_ptr) { AVPacket *pkt_temp = &is->audio_pkt_temp; AVPacket *pkt = &is->audio_pkt; - AVCodecContext *dec = is->audio_st->codec; + AVCodecContext *dec = is->audio_dec; int n, len1, data_size, got_frame; double pts; int new_packet = 0; @@ -1863,7 +1822,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; } @@ -1959,7 +1918,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) { @@ -1987,11 +1946,11 @@ static int audio_decode_frame(VideoState *is, double *pts_ptr) /* prepare a new audio buffer */ static void sdl_audio_callback(void *opaque, Uint8 *stream, int len) { - VideoState *is = opaque; + PlayerState *is = opaque; 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) { @@ -2019,8 +1978,54 @@ static void sdl_audio_callback(void *opaque, Uint8 *stream, int len) } } +static AVCodec *find_codec_or_die(const char *name, enum AVMediaType type) +{ + const AVCodecDescriptor *desc; + AVCodec *codec = avcodec_find_decoder_by_name(name); + + if (!codec && (desc = avcodec_descriptor_get_by_name(name))) { + codec = avcodec_find_decoder(desc->id); + if (codec) + av_log(NULL, AV_LOG_VERBOSE, "Matched decoder '%s' for codec '%s'.\n", + codec->name, desc->name); + } + + if (!codec) { + av_log(NULL, AV_LOG_FATAL, "Unknown decoder '%s'\n", name); + exit_program(1); + } + + if (codec->type != type) { + av_log(NULL, AV_LOG_FATAL, "Invalid decoder type '%s'\n", name); + exit_program(1); + } + + return codec; +} + +static AVCodec *choose_decoder(PlayerState *is, AVFormatContext *ic, AVStream *st) +{ + char *codec_name = NULL; + int i, ret; + + for (i = 0; i < is->nb_codec_names; i++) { + char *spec = is->codec_names[i].specifier; + if ((ret = check_stream_specifier(ic, st, spec)) > 0) + codec_name = is->codec_names[i].u.str; + else if (ret < 0) + exit_program(1); + } + + if (codec_name) { + AVCodec *codec = find_codec_or_die(codec_name, st->codecpar->codec_type); + st->codecpar->codec_id = codec->id; + return codec; + } else + return avcodec_find_decoder(st->codecpar->codec_id); +} + /* open a given stream. Return 0 if OK */ -static int stream_component_open(VideoState *is, int stream_index) +static int stream_component_open(PlayerState *is, int stream_index) { AVFormatContext *ic = is->ic; AVCodecContext *avctx; @@ -2028,14 +2033,24 @@ 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; - avctx = ic->streams[stream_index]->codec; + + avctx = avcodec_alloc_context3(NULL); + if (!avctx) + return AVERROR(ENOMEM); + + ret = avcodec_parameters_to_context(avctx, ic->streams[stream_index]->codecpar); + if (ret < 0) { + avcodec_free_context(&avctx); + return ret; + } opts = filter_codec_opts(codec_opts, avctx->codec_id, ic, ic->streams[stream_index], NULL); - codec = avcodec_find_decoder(avctx->codec_id); + codec = choose_decoder(is, ic, ic->streams[stream_index]); avctx->workaround_bugs = workaround_bugs; avctx->idct_algo = idct; avctx->skip_frame = skip_frame; @@ -2043,18 +2058,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 */ @@ -2065,7 +2083,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; @@ -2082,7 +2101,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; @@ -2096,13 +2116,14 @@ static int stream_component_open(VideoState *is, int stream_index) case AVMEDIA_TYPE_AUDIO: is->audio_stream = stream_index; is->audio_st = ic->streams[stream_index]; + is->audio_dec = avctx; is->audio_buf_size = 0; is->audio_buf_index = 0; /* init averaging filter */ is->audio_diff_avg_coef = exp(log(0.01) / AUDIO_DIFF_AVG_NB); is->audio_diff_avg_count = 0; - /* since we do not have a precise anough audio fifo fullness, + /* since we do not have a precise enough audio FIFO fullness, we correct audio sync only if larger than this threshold */ is->audio_diff_threshold = 2.0 * SDL_AUDIO_BUFFER_SIZE / avctx->sample_rate; @@ -2113,6 +2134,7 @@ static int stream_component_open(VideoState *is, int stream_index) case AVMEDIA_TYPE_VIDEO: is->video_stream = stream_index; is->video_st = ic->streams[stream_index]; + is->video_dec = avctx; packet_queue_init(&is->videoq); is->video_tid = SDL_CreateThread(video_thread, is); @@ -2120,6 +2142,7 @@ static int stream_component_open(VideoState *is, int stream_index) case AVMEDIA_TYPE_SUBTITLE: is->subtitle_stream = stream_index; is->subtitle_st = ic->streams[stream_index]; + is->subtitle_dec = avctx; packet_queue_init(&is->subtitleq); is->subtitle_tid = SDL_CreateThread(subtitle_thread, is); @@ -2127,26 +2150,30 @@ 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) +static void stream_component_close(PlayerState *is, int stream_index) { AVFormatContext *ic = is->ic; - AVCodecContext *avctx; + AVCodecParameters *par; if (stream_index < 0 || stream_index >= ic->nb_streams) return; - avctx = ic->streams[stream_index]->codec; + par = ic->streams[stream_index]->codecpar; - switch (avctx->codec_type) { + switch (par->codec_type) { case AVMEDIA_TYPE_AUDIO: packet_queue_abort(&is->audioq); 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); @@ -2193,17 +2220,19 @@ static void stream_component_close(VideoState *is, int stream_index) } ic->streams[stream_index]->discard = AVDISCARD_ALL; - avcodec_close(avctx); - switch (avctx->codec_type) { + switch (par->codec_type) { case AVMEDIA_TYPE_AUDIO: + avcodec_free_context(&is->audio_dec); is->audio_st = NULL; is->audio_stream = -1; break; case AVMEDIA_TYPE_VIDEO: + avcodec_free_context(&is->video_dec); is->video_st = NULL; is->video_stream = -1; break; case AVMEDIA_TYPE_SUBTITLE: + avcodec_free_context(&is->subtitle_dec); is->subtitle_st = NULL; is->subtitle_stream = -1; break; @@ -2214,23 +2243,35 @@ static void stream_component_close(VideoState *is, int stream_index) /* since we have only one decoding thread, we can use a global variable instead of a thread local variable */ -static VideoState *global_video_state; +static PlayerState *global_video_state; static int decode_interrupt_cb(void *ctx) { return global_video_state && global_video_state->abort_request; } -/* this thread gets the stream from the disk or the network */ -static int decode_thread(void *arg) +static void stream_close(PlayerState *is) +{ + /* disable interrupting */ + global_video_state = NULL; + + /* 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 (is->ic) { + avformat_close_input(&is->ic); + } +} + +static int stream_setup(PlayerState *is) { - VideoState *is = arg; AVFormatContext *ic = NULL; int err, i, ret; int st_index[AVMEDIA_TYPE_NB]; - AVPacket pkt1, *pkt = &pkt1; - int eof = 0; - int pkt_in_play_range = 0; AVDictionaryEntry *t; AVDictionary **opts; int orig_nb_streams; @@ -2243,6 +2284,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) { @@ -2250,6 +2296,7 @@ static int decode_thread(void *arg) ret = -1; goto fail; } + if ((t = av_dict_get(format_opts, "", NULL, AV_DICT_IGNORE_SUFFIX))) { av_log(NULL, AV_LOG_ERROR, "Option %s not found.\n", t->key); ret = AVERROR_OPTION_NOT_FOUND; @@ -2263,15 +2310,20 @@ static int decode_thread(void *arg) opts = setup_find_stream_info_opts(ic, codec_opts); orig_nb_streams = ic->nb_streams; + for (i = 0; i < ic->nb_streams; i++) + choose_decoder(is, ic, ic->streams[i]); + 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 @@ -2327,7 +2379,6 @@ static int decode_thread(void *arg) if (st_index[AVMEDIA_TYPE_VIDEO] >= 0) { ret = stream_component_open(is, st_index[AVMEDIA_TYPE_VIDEO]); } - is->refresh_tid = SDL_CreateThread(refresh_thread, is); if (ret < 0) { if (!display_disable) is->show_audio = 2; @@ -2343,6 +2394,21 @@ static int decode_thread(void *arg) goto fail; } + return 0; + +fail: + return ret; +} + +/* this thread gets the stream from the disk or the network */ +static int decode_thread(void *arg) +{ + PlayerState *is = arg; + AVPacket pkt1, *pkt = &pkt1; + AVFormatContext *ic = is->ic; + int pkt_in_play_range = 0; + int ret, eof = 0; + for (;;) { if (is->abort_request) break; @@ -2408,7 +2474,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_dec->codec->capabilities & AV_CODEC_CAP_DELAY)) { av_init_packet(pkt); pkt->data = NULL; pkt->size = 0; @@ -2418,8 +2484,8 @@ static int decode_thread(void *arg) SDL_Delay(10); 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) { + stream_seek(player, start_time != AV_NOPTS_VALUE ? start_time : 0, 0, 0); + } else if (!noautoexit) { ret = AVERROR_EOF; goto fail; } @@ -2448,7 +2514,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 */ @@ -2457,20 +2523,9 @@ static int decode_thread(void *arg) } ret = 0; - fail: - /* disable interrupting */ - global_video_state = NULL; - /* 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 (is->ic) { - avformat_close_input(&is->ic); - } +fail: + stream_close(is); if (ret != 0) { SDL_Event event; @@ -2482,18 +2537,20 @@ static int decode_thread(void *arg) return 0; } -static VideoState *stream_open(const char *filename, AVInputFormat *iformat) +static int stream_open(PlayerState *is, + const char *filename, AVInputFormat *iformat) { - VideoState *is; + int ret; - is = av_mallocz(sizeof(VideoState)); - if (!is) - return NULL; av_strlcpy(is->filename, filename, sizeof(is->filename)); is->iformat = iformat; is->ytop = 0; is->xleft = 0; + if ((ret = stream_setup(is)) < 0) { + return ret; + } + /* start video display */ is->pictq_mutex = SDL_CreateMutex(); is->pictq_cond = SDL_CreateCond(); @@ -2502,15 +2559,16 @@ static VideoState *stream_open(const char *filename, AVInputFormat *iformat) is->subpq_cond = SDL_CreateCond(); is->av_sync_type = av_sync_type; + is->refresh_tid = SDL_CreateThread(refresh_thread, is); + if (!is->refresh_tid) + return -1; is->parse_tid = SDL_CreateThread(decode_thread, is); - if (!is->parse_tid) { - av_free(is); - return NULL; - } - return is; + if (!is->parse_tid) + return -1; + return 0; } -static void stream_cycle_channel(VideoState *is, int codec_type) +static void stream_cycle_channel(PlayerState *is, int codec_type) { AVFormatContext *ic = is->ic; int start_index, stream_index; @@ -2538,12 +2596,12 @@ static void stream_cycle_channel(VideoState *is, int codec_type) if (stream_index == start_index) return; st = ic->streams[stream_index]; - if (st->codec->codec_type == codec_type) { + if (st->codecpar->codec_type == codec_type) { /* check that parameters are OK */ switch (codec_type) { case AVMEDIA_TYPE_AUDIO: - if (st->codec->sample_rate != 0 && - st->codec->channels != 0) + if (st->codecpar->sample_rate != 0 && + st->codecpar->channels != 0) goto the_end; break; case AVMEDIA_TYPE_VIDEO: @@ -2566,42 +2624,42 @@ static void toggle_full_screen(void) /* OS X needs to empty the picture_queue */ int i; for (i = 0; i < VIDEO_PICTURE_QUEUE_SIZE; i++) - cur_stream->pictq[i].reallocate = 1; + player->pictq[i].reallocate = 1; #endif is_full_screen = !is_full_screen; - video_open(cur_stream); + video_open(player); } static void toggle_pause(void) { - if (cur_stream) - stream_pause(cur_stream); + if (player) + stream_pause(player); step = 0; } static void step_to_next_frame(void) { - if (cur_stream) { + if (player) { /* if the stream is paused unpause it, then step */ - if (cur_stream->paused) - stream_pause(cur_stream); + if (player->paused) + stream_pause(player); } step = 1; } static void toggle_audio_display(void) { - if (cur_stream) { + if (player) { int bgcolor = SDL_MapRGB(screen->format, 0x00, 0x00, 0x00); - cur_stream->show_audio = (cur_stream->show_audio + 1) % 3; + player->show_audio = (player->show_audio + 1) % 3; fill_rectangle(screen, - cur_stream->xleft, cur_stream->ytop, cur_stream->width, cur_stream->height, + player->xleft, player->ytop, player->width, player->height, bgcolor); - SDL_UpdateRect(screen, cur_stream->xleft, cur_stream->ytop, cur_stream->width, cur_stream->height); + SDL_UpdateRect(screen, player->xleft, player->ytop, player->width, player->height); } } -static void seek_chapter(VideoState *is, int incr) +static void seek_chapter(PlayerState *is, int incr) { int64_t pos = get_master_clock(is) * AV_TIME_BASE; int i; @@ -2659,25 +2717,25 @@ static void event_loop(void) step_to_next_frame(); break; case SDLK_a: - if (cur_stream) - stream_cycle_channel(cur_stream, AVMEDIA_TYPE_AUDIO); + if (player) + stream_cycle_channel(player, AVMEDIA_TYPE_AUDIO); break; case SDLK_v: - if (cur_stream) - stream_cycle_channel(cur_stream, AVMEDIA_TYPE_VIDEO); + if (player) + stream_cycle_channel(player, AVMEDIA_TYPE_VIDEO); break; case SDLK_t: - if (cur_stream) - stream_cycle_channel(cur_stream, AVMEDIA_TYPE_SUBTITLE); + if (player) + stream_cycle_channel(player, AVMEDIA_TYPE_SUBTITLE); break; case SDLK_w: toggle_audio_display(); break; case SDLK_PAGEUP: - seek_chapter(cur_stream, 1); + seek_chapter(player, 1); break; case SDLK_PAGEDOWN: - seek_chapter(cur_stream, -1); + seek_chapter(player, -1); break; case SDLK_LEFT: incr = -10.0; @@ -2691,24 +2749,24 @@ static void event_loop(void) case SDLK_DOWN: incr = -60.0; do_seek: - if (cur_stream) { + if (player) { if (seek_by_bytes) { - if (cur_stream->video_stream >= 0 && cur_stream->video_current_pos >= 0) { - pos = cur_stream->video_current_pos; - } else if (cur_stream->audio_stream >= 0 && cur_stream->audio_pkt.pos >= 0) { - pos = cur_stream->audio_pkt.pos; + if (player->video_stream >= 0 && player->video_current_pos >= 0) { + pos = player->video_current_pos; + } else if (player->audio_stream >= 0 && player->audio_pkt.pos >= 0) { + pos = player->audio_pkt.pos; } else - pos = avio_tell(cur_stream->ic->pb); - if (cur_stream->ic->bit_rate) - incr *= cur_stream->ic->bit_rate / 8.0; + pos = avio_tell(player->ic->pb); + if (player->ic->bit_rate) + incr *= player->ic->bit_rate / 8.0; else incr *= 180000.0; pos += incr; - stream_seek(cur_stream, pos, incr, 1); + stream_seek(player, pos, incr, 1); } else { - pos = get_master_clock(cur_stream); + pos = get_master_clock(player); pos += incr; - stream_seek(cur_stream, (int64_t)(pos * AV_TIME_BASE), (int64_t)(incr * AV_TIME_BASE), 0); + stream_seek(player, (int64_t)(pos * AV_TIME_BASE), (int64_t)(incr * AV_TIME_BASE), 0); } } break; @@ -2729,38 +2787,38 @@ static void event_loop(void) break; x = event.motion.x; } - if (cur_stream) { - if (seek_by_bytes || cur_stream->ic->duration <= 0) { - uint64_t size = avio_size(cur_stream->ic->pb); - stream_seek(cur_stream, size*x/cur_stream->width, 0, 1); + if (player) { + if (seek_by_bytes || player->ic->duration <= 0) { + uint64_t size = avio_size(player->ic->pb); + stream_seek(player, size*x/player->width, 0, 1); } else { int64_t ts; int ns, hh, mm, ss; int tns, thh, tmm, tss; - tns = cur_stream->ic->duration / 1000000LL; + tns = player->ic->duration / 1000000LL; thh = tns / 3600; tmm = (tns % 3600) / 60; tss = (tns % 60); - frac = x / cur_stream->width; + frac = x / player->width; ns = frac * tns; hh = ns / 3600; mm = (ns % 3600) / 60; ss = (ns % 60); fprintf(stderr, "Seek to %2.0f%% (%2d:%02d:%02d) of total duration (%2d:%02d:%02d) \n", frac*100, hh, mm, ss, thh, tmm, tss); - ts = frac * cur_stream->ic->duration; - if (cur_stream->ic->start_time != AV_NOPTS_VALUE) - ts += cur_stream->ic->start_time; - stream_seek(cur_stream, ts, 0, 0); + ts = frac * player->ic->duration; + if (player->ic->start_time != AV_NOPTS_VALUE) + ts += player->ic->start_time; + stream_seek(player, ts, 0, 0); } } break; case SDL_VIDEORESIZE: - if (cur_stream) { + if (player) { screen = SDL_SetVideoMode(event.resize.w, event.resize.h, 0, SDL_HWSURFACE|SDL_RESIZABLE|SDL_ASYNCBLIT|SDL_HWACCEL); - screen_width = cur_stream->width = event.resize.w; - screen_height = cur_stream->height = event.resize.h; + screen_width = player->width = event.resize.w; + screen_height = player->height = event.resize.h; } break; case SDL_QUIT: @@ -2773,7 +2831,7 @@ static void event_loop(void) break; case FF_REFRESH_EVENT: video_refresh_timer(event.user.data1); - cur_stream->refresh = 0; + player->refresh = 0; break; default: break; @@ -2844,6 +2902,7 @@ static int opt_duration(void *optctx, const char *opt, const char *arg) return 0; } +#define OFF(x) offsetof(PlayerState, x) static const OptionDef options[] = { #include "cmdutils_common_opts.h" { "x", HAS_ARG, { .func_arg = opt_width }, "force displayed width", "width" }, @@ -2872,19 +2931,21 @@ 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" }, { "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_STRING | HAS_ARG, { &vfilters }, "video filters", "filter list" }, -#endif { "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", "" }, + { "default", HAS_ARG | OPT_AUDIO | OPT_VIDEO | OPT_EXPERT, { .func_arg = opt_default }, "generic catchall option", "" }, { "i", 0, { NULL }, "avconv compatibility dummy option", ""}, + { "autorotate", OPT_BOOL, { &autorotate }, "automatically rotate video", "" }, + { "c", HAS_ARG | OPT_STRING | OPT_SPEC | OPT_INPUT, { .off = OFF(codec_names) }, "codec name", "codec" }, + { "codec", HAS_ARG | OPT_STRING | OPT_SPEC | OPT_INPUT, { .off = OFF(codec_names) }, "codec name", "codec" }, + { NULL, }, }; @@ -2904,9 +2965,6 @@ void show_help_default(const char *opt, const char *arg) printf("\n"); 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); -#endif printf("\nWhile playing:\n" "q, ESC quit\n" "f toggle full screen\n" @@ -2947,9 +3005,7 @@ int main(int argc, char **argv) #if CONFIG_AVDEVICE avdevice_register_all(); #endif -#if CONFIG_AVFILTER avfilter_register_all(); -#endif av_register_all(); avformat_network_init(); @@ -2957,7 +3013,7 @@ int main(int argc, char **argv) show_banner(); - parse_options(NULL, argc, argv, options, opt_input_file); + parse_options(player, argc, argv, options, opt_input_file); if (!input_filename) { show_usage(); @@ -2991,7 +3047,11 @@ int main(int argc, char **argv) av_init_packet(&flush_pkt); flush_pkt.data = (uint8_t *)&flush_pkt; - cur_stream = stream_open(input_filename, file_iformat); + if (stream_open(player, input_filename, file_iformat) < 0) { + fprintf(stderr, "Could not setup the player\n"); + stream_close(player); + exit(1); + } event_loop();