X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=avplay.c;h=90147ceb2735b16d0eea058b735d8a221775af75;hb=dd53af4b37c7790ce26065b36d5655c1af38b295;hp=0c642e07b0b994c6f33df27d1e6a451cf4982d36;hpb=f9fada2704df7994e8e4451ac78d8d5569faa8a2;p=ffmpeg diff --git a/avplay.c b/avplay.c index 0c642e07b0b..90147ceb273 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" @@ -34,17 +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/avfiltergraph.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" @@ -84,7 +83,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 +98,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 { @@ -124,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; @@ -164,8 +161,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,20 +190,17 @@ 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; SDL_cond *pictq_cond; -#if !CONFIG_AVFILTER - struct SwsContext *img_convert_ctx; -#endif // QETimer *video_timer; char filename[1024]; @@ -212,17 +208,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 - int use_dr1; - FrameBuffer *buffer_pool; -#endif + AVFilterContext *in_video_filter; // the first filter in the video chain + AVFilterContext *out_video_filter; // the last filter in the video chain 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; @@ -245,8 +240,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 +250,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,13 +258,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; @@ -282,11 +275,6 @@ static AVPacket flush_pkt; static SDL_Surface *screen; -void exit_program(int ret) -{ - exit(ret); -} - static int packet_queue_put(PacketQueue *q, AVPacket *pkt); /* packet queue handling */ @@ -305,7 +293,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; @@ -326,10 +314,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; @@ -441,7 +425,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; @@ -454,16 +439,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; @@ -509,8 +495,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; @@ -594,8 +580,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) { @@ -646,11 +632,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; @@ -658,21 +643,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); -#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 + aspect_ratio = av_q2d(vp->sar); if (aspect_ratio <= 0.0) aspect_ratio = 1.0; aspect_ratio *= (float)vp->width / (float)vp->height; @@ -687,17 +661,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); } @@ -725,7 +691,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; } @@ -739,7 +705,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; @@ -762,8 +728,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; @@ -856,7 +822,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])); @@ -878,7 +845,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; @@ -892,15 +859,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; @@ -930,10 +891,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) @@ -942,7 +903,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; @@ -957,7 +918,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; @@ -965,7 +926,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,25 +935,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; @@ -1013,7 +974,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; @@ -1026,21 +987,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; @@ -1072,7 +1033,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; @@ -1081,7 +1042,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; @@ -1091,7 +1052,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]; @@ -1197,7 +1158,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; @@ -1220,7 +1181,7 @@ retry: } } -static void stream_close(VideoState *is) +static void player_close(PlayerState *is) { VideoPicture *vp; int i; @@ -1232,9 +1193,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; @@ -1244,23 +1202,15 @@ 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(); -#if CONFIG_AVFILTER - avfilter_uninit(); -#endif avformat_network_deinit(); if (show_status) printf("\n"); @@ -1273,7 +1223,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]; @@ -1281,17 +1231,9 @@ static void alloc_picture(void *opaque) if (vp->bmp) 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; -#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, @@ -1311,18 +1253,12 @@ 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 - */ -static int queue_picture(VideoState *is, AVFrame *src_frame, double pts, int64_t pos) +/* The 'pts' parameter is the dts of the packet / pts of the frame and + * guessed if not known. */ +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 = PIX_FMT_YUV420P; -#endif + /* wait until we have space to put a new picture */ SDL_LockMutex(is->pictq_mutex); @@ -1340,15 +1276,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; @@ -1373,47 +1306,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 } }; -#if CONFIG_AVFILTER - avfilter_unref_bufferp(&vp->picref); - vp->picref = src_frame->opaque; -#endif + 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]; - - 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]; + data[0] = vp->bmp->pixels[0]; + data[1] = vp->bmp->pixels[2]; + data[2] = vp->bmp->pixels[1]; - 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 - sws_flags = av_get_int(sws_opts, "sws_flags", NULL); - 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); @@ -1432,13 +1342,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 - */ -static int output_picture2(VideoState *is, AVFrame *src_frame, double pts1, int64_t pos) +/* 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(PlayerState *is, AVFrame *src_frame, double pts1, int64_t pos) { double frame_delay, pts; + int ret; pts = pts1; @@ -1455,10 +1364,12 @@ 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) +static int get_video_frame(PlayerState *is, AVFrame *frame, int64_t *pts, AVPacket *pkt) { int got_picture, i; @@ -1482,7 +1393,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,27 +1413,29 @@ 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; } -#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; + 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", @@ -1541,13 +1454,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(); @@ -1559,14 +1502,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; } @@ -1576,49 +1519,43 @@ 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; } -#endif /* CONFIG_AVFILTER */ - static int video_thread(void *arg) { AVPacket pkt = { 0 }; - VideoState *is = arg; - AVFrame *frame = avcodec_alloc_frame(); + 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; - 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; 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 - AVFilterBufferRef *picref; 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) @@ -1627,10 +1564,9 @@ 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, + 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(); @@ -1643,74 +1579,50 @@ 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); - 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_free(frame); + 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; @@ -1757,11 +1669,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); } } @@ -1772,13 +1684,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; @@ -1798,7 +1710,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; @@ -1826,7 +1738,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; @@ -1856,7 +1768,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); } @@ -1872,7 +1784,7 @@ 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; @@ -1888,10 +1800,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; @@ -1908,19 +1819,21 @@ 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; } 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; @@ -1934,20 +1847,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) { @@ -1966,9 +1880,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) { @@ -1986,7 +1900,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; @@ -2001,7 +1915,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) { @@ -2029,11 +1943,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) { @@ -2061,8 +1975,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->codec->codec_type); + st->codec->codec_id = codec->id; + return codec; + } else + return avcodec_find_decoder(st->codec->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; @@ -2070,6 +2030,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; @@ -2077,9 +2038,7 @@ 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; + codec = choose_decoder(is, ic, ic->streams[stream_index]); avctx->workaround_bugs = workaround_bugs; avctx->idct_algo = idct; avctx->skip_frame = skip_frame; @@ -2087,28 +2046,33 @@ 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 */ 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; @@ -2116,6 +2080,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; @@ -2123,12 +2089,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; @@ -2167,10 +2135,14 @@ 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; @@ -2186,12 +2158,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; - av_freep(&is->frame); + av_frame_free(&is->frame); if (is->rdft) { av_rdft_end(is->rdft); @@ -2234,9 +2206,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; @@ -2257,23 +2226,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; @@ -2286,6 +2267,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) { @@ -2293,6 +2279,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; @@ -2306,15 +2293,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++) + ic->streams[i]->codec->codec = 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 @@ -2370,7 +2362,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; @@ -2386,6 +2377,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; @@ -2451,7 +2457,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; @@ -2461,8 +2467,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; } @@ -2491,7 +2497,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 */ @@ -2500,20 +2506,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; @@ -2525,18 +2520,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(); @@ -2545,15 +2542,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; @@ -2609,39 +2607,66 @@ 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(PlayerState *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 */ @@ -2675,20 +2700,26 @@ 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(player, 1); + break; + case SDLK_PAGEDOWN: + seek_chapter(player, -1); + break; case SDLK_LEFT: incr = -10.0; goto do_seek; @@ -2701,24 +2732,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; @@ -2739,38 +2770,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: @@ -2783,7 +2814,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; @@ -2791,26 +2822,26 @@ static void event_loop(void) } } -static int opt_frame_size(const char *opt, const char *arg) +static int opt_frame_size(void *optctx, const char *opt, const char *arg) { av_log(NULL, AV_LOG_ERROR, "Option '%s' has been removed, use private format options instead\n", opt); return AVERROR(EINVAL); } -static int opt_width(const char *opt, const char *arg) +static int opt_width(void *optctx, const char *opt, const char *arg) { screen_width = parse_number_or_die(opt, arg, OPT_INT64, 1, INT_MAX); return 0; } -static int opt_height(const char *opt, const char *arg) +static int opt_height(void *optctx, const char *opt, const char *arg) { screen_height = parse_number_or_die(opt, arg, OPT_INT64, 1, INT_MAX); return 0; } -static int opt_format(const char *opt, const char *arg) +static int opt_format(void *optctx, const char *opt, const char *arg) { file_iformat = av_find_input_format(arg); if (!file_iformat) { @@ -2820,14 +2851,14 @@ static int opt_format(const char *opt, const char *arg) return 0; } -static int opt_frame_pix_fmt(const char *opt, const char *arg) +static int opt_frame_pix_fmt(void *optctx, const char *opt, const char *arg) { av_log(NULL, AV_LOG_ERROR, "Option '%s' has been removed, use private format options instead\n", opt); return AVERROR(EINVAL); } -static int opt_sync(const char *opt, const char *arg) +static int opt_sync(void *optctx, const char *opt, const char *arg) { if (!strcmp(arg, "audio")) av_sync_type = AV_SYNC_AUDIO_MASTER; @@ -2842,74 +2873,62 @@ static int opt_sync(const char *opt, const char *arg) return 0; } -static int opt_seek(const char *opt, const char *arg) +static int opt_seek(void *optctx, const char *opt, const char *arg) { start_time = parse_time_or_die(opt, arg, 1); return 0; } -static int opt_duration(const char *opt, const char *arg) +static int opt_duration(void *optctx, const char *opt, const char *arg) { duration = parse_time_or_die(opt, arg, 1); return 0; } -static int opt_debug(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(const char *opt, const char *arg) -{ - debug_mv = parse_number_or_die(opt, arg, OPT_INT64, INT_MIN, INT_MAX); - return 0; -} - +#define OFF(x) offsetof(PlayerState, x) static const OptionDef options[] = { #include "cmdutils_common_opts.h" - { "x", HAS_ARG, { (void*)opt_width }, "force displayed width", "width" }, - { "y", HAS_ARG, { (void*)opt_height }, "force displayed height", "height" }, - { "s", HAS_ARG | OPT_VIDEO, { (void*)opt_frame_size }, "set frame size (WxH or abbreviation)", "size" }, - { "fs", OPT_BOOL, { (void*)&is_full_screen }, "force full screen" }, - { "an", OPT_BOOL, { (void*)&audio_disable }, "disable audio" }, - { "vn", OPT_BOOL, { (void*)&video_disable }, "disable video" }, - { "ast", OPT_INT | HAS_ARG | OPT_EXPERT, { (void*)&wanted_stream[AVMEDIA_TYPE_AUDIO] }, "select desired audio stream", "stream_number" }, - { "vst", OPT_INT | HAS_ARG | OPT_EXPERT, { (void*)&wanted_stream[AVMEDIA_TYPE_VIDEO] }, "select desired video stream", "stream_number" }, - { "sst", OPT_INT | HAS_ARG | OPT_EXPERT, { (void*)&wanted_stream[AVMEDIA_TYPE_SUBTITLE] }, "select desired subtitle stream", "stream_number" }, - { "ss", HAS_ARG, { (void*)&opt_seek }, "seek to a given position in seconds", "pos" }, - { "t", HAS_ARG, { (void*)&opt_duration }, "play \"duration\" seconds of audio/video", "duration" }, - { "bytes", OPT_INT | HAS_ARG, { (void*)&seek_by_bytes }, "seek by bytes 0=off 1=on -1=auto", "val" }, - { "nodisp", OPT_BOOL, { (void*)&display_disable }, "disable graphical display" }, - { "f", HAS_ARG, { (void*)opt_format }, "force format", "fmt" }, - { "pix_fmt", HAS_ARG | OPT_EXPERT | OPT_VIDEO, { (void*)opt_frame_pix_fmt }, "set pixel format", "format" }, - { "stats", OPT_BOOL | OPT_EXPERT, { (void*)&show_status }, "show status", "" }, - { "debug", HAS_ARG | OPT_EXPERT, { (void*)opt_debug }, "print specific debug info", "" }, - { "bug", OPT_INT | HAS_ARG | OPT_EXPERT, { (void*)&workaround_bugs }, "workaround bugs", "" }, - { "vismv", HAS_ARG | OPT_EXPERT, { (void*)opt_vismv }, "visualize motion vectors", "" }, - { "fast", OPT_BOOL | OPT_EXPERT, { (void*)&fast }, "non spec compliant optimizations", "" }, - { "genpts", OPT_BOOL | OPT_EXPERT, { (void*)&genpts }, "generate pts", "" }, - { "drp", OPT_INT | HAS_ARG | OPT_EXPERT, { (void*)&decoder_reorder_pts }, "let decoder reorder pts 0=off 1=on -1=auto", ""}, - { "skiploop", OPT_INT | HAS_ARG | OPT_EXPERT, { (void*)&skip_loop_filter }, "", "" }, - { "skipframe", OPT_INT | HAS_ARG | OPT_EXPERT, { (void*)&skip_frame }, "", "" }, - { "skipidct", OPT_INT | HAS_ARG | OPT_EXPERT, { (void*)&skip_idct }, "", "" }, - { "idct", OPT_INT | HAS_ARG | OPT_EXPERT, { (void*)&idct }, "set idct algo", "algo" }, - { "ec", OPT_INT | HAS_ARG | OPT_EXPERT, { (void*)&error_concealment }, "set error concealment options", "bit_mask" }, - { "sync", HAS_ARG | OPT_EXPERT, { (void*)opt_sync }, "set audio-video sync. type (type=audio/video/ext)", "type" }, - { "autoexit", OPT_BOOL | OPT_EXPERT, { (void*)&autoexit }, "exit at the end", "" }, - { "exitonkeydown", OPT_BOOL | OPT_EXPERT, { (void*)&exit_on_keydown }, "exit on key down", "" }, - { "exitonmousedown", OPT_BOOL | OPT_EXPERT, { (void*)&exit_on_mousedown }, "exit on mouse down", "" }, - { "loop", OPT_INT | HAS_ARG | OPT_EXPERT, { (void*)&loop }, "set number of times the playback shall be looped", "loop count" }, - { "framedrop", OPT_BOOL | OPT_EXPERT, { (void*)&framedrop }, "drop frames when cpu is too slow", "" }, - { "infbuf", OPT_BOOL | OPT_EXPERT, { (void*)&infinite_buffer }, "don't limit the input buffer size (useful with realtime streams)", "" }, - { "window_title", OPT_STRING | HAS_ARG, { (void*)&window_title }, "set window title", "window title" }, -#if CONFIG_AVFILTER - { "vf", OPT_STRING | HAS_ARG, { (void*)&vfilters }, "video filters", "filter list" }, -#endif - { "rdftspeed", OPT_INT | HAS_ARG| OPT_AUDIO | OPT_EXPERT, { (void*)&rdftspeed }, "rdft speed", "msecs" }, - { "default", HAS_ARG | OPT_AUDIO | OPT_VIDEO | OPT_EXPERT, { (void*)opt_default }, "generic catch all option", "" }, + { "x", HAS_ARG, { .func_arg = opt_width }, "force displayed width", "width" }, + { "y", HAS_ARG, { .func_arg = opt_height }, "force displayed height", "height" }, + { "s", HAS_ARG | OPT_VIDEO, { .func_arg = opt_frame_size }, "set frame size (WxH or abbreviation)", "size" }, + { "fs", OPT_BOOL, { &is_full_screen }, "force full screen" }, + { "an", OPT_BOOL, { &audio_disable }, "disable audio" }, + { "vn", OPT_BOOL, { &video_disable }, "disable video" }, + { "ast", OPT_INT | HAS_ARG | OPT_EXPERT, { &wanted_stream[AVMEDIA_TYPE_AUDIO] }, "select desired audio stream", "stream_number" }, + { "vst", OPT_INT | HAS_ARG | OPT_EXPERT, { &wanted_stream[AVMEDIA_TYPE_VIDEO] }, "select desired video stream", "stream_number" }, + { "sst", OPT_INT | HAS_ARG | OPT_EXPERT, { &wanted_stream[AVMEDIA_TYPE_SUBTITLE] }, "select desired subtitle stream", "stream_number" }, + { "ss", HAS_ARG, { .func_arg = opt_seek }, "seek to a given position in seconds", "pos" }, + { "t", HAS_ARG, { .func_arg = opt_duration }, "play \"duration\" seconds of audio/video", "duration" }, + { "bytes", OPT_INT | HAS_ARG, { &seek_by_bytes }, "seek by bytes 0=off 1=on -1=auto", "val" }, + { "nodisp", OPT_BOOL, { &display_disable }, "disable graphical display" }, + { "f", HAS_ARG, { .func_arg = opt_format }, "force format", "fmt" }, + { "pix_fmt", HAS_ARG | OPT_EXPERT | OPT_VIDEO, { .func_arg = opt_frame_pix_fmt }, "set pixel format", "format" }, + { "stats", OPT_BOOL | OPT_EXPERT, { &show_status }, "show status", "" }, + { "bug", OPT_INT | HAS_ARG | OPT_EXPERT, { &workaround_bugs }, "workaround bugs", "" }, + { "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", ""}, + { "skiploop", OPT_INT | HAS_ARG | OPT_EXPERT, { &skip_loop_filter }, "", "" }, + { "skipframe", OPT_INT | HAS_ARG | OPT_EXPERT, { &skip_frame }, "", "" }, + { "skipidct", OPT_INT | HAS_ARG | OPT_EXPERT, { &skip_idct }, "", "" }, + { "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" }, + { "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" }, + { "vf", OPT_STRING | HAS_ARG, { &vfilters }, "video filters", "filter list" }, + { "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", "" }, + { "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, }, }; @@ -2929,9 +2948,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" @@ -2972,9 +2988,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(); @@ -2982,7 +2996,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(); @@ -3004,11 +3018,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); @@ -3016,9 +3028,13 @@ 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); + if (stream_open(player, input_filename, file_iformat) < 0) { + fprintf(stderr, "Could not setup the player\n"); + stream_close(player); + exit(1); + } event_loop();