#define AUDIO_DIFF_AVG_NB 20
/* NOTE: the size must be big enough to compensate the hardware audio buffersize size */
-#define SAMPLE_ARRAY_SIZE (2 * 65536)
+/* TODO: We assume that a decoded and resampled frame fits into this buffer */
+#define SAMPLE_ARRAY_SIZE (8 * 65536)
static int sws_flags = SWS_BICUBIC;
SDL_cond *cond;
} PacketQueue;
-#define VIDEO_PICTURE_QUEUE_SIZE 3
+#define VIDEO_PICTURE_QUEUE_SIZE 4
#define SUBPICTURE_QUEUE_SIZE 4
typedef struct VideoPicture {
SDL_cond *continue_read_thread;
} VideoState;
-typedef struct AllocEventProps {
- VideoState *is;
- AVFrame *frame;
-} AllocEventProps;
-
/* options specified by the user */
static AVInputFormat *file_iformat;
static const char *input_filename;
static int exit_on_mousedown;
static int loop = 1;
static int framedrop = -1;
-static int infinite_buffer = 0;
+static int infinite_buffer = -1;
static enum ShowMode show_mode = SHOW_MODE_NONE;
static const char *audio_codec_name;
static const char *subtitle_codec_name;
static SDL_Surface *screen;
-void av_noreturn exit_program(int ret)
-{
- exit(ret);
-}
+static int packet_queue_put(PacketQueue *q, AVPacket *pkt);
static int packet_queue_put_private(PacketQueue *q, AVPacket *pkt)
{
avsubtitle_free(&sp->sub);
}
+static void calculate_display_rect(SDL_Rect *rect, int scr_xleft, int scr_ytop, int scr_width, int scr_height, VideoPicture *vp)
+{
+ float aspect_ratio;
+ int width, height, x, y;
+
+ if (vp->sample_aspect_ratio.num == 0)
+ aspect_ratio = 0;
+ else
+ aspect_ratio = av_q2d(vp->sample_aspect_ratio);
+
+ if (aspect_ratio <= 0.0)
+ aspect_ratio = 1.0;
+ aspect_ratio *= (float)vp->width / (float)vp->height;
+
+ /* XXX: we suppose the screen has a 1.0 pixel ratio */
+ height = scr_height;
+ width = ((int)rint(height * aspect_ratio)) & ~1;
+ if (width > scr_width) {
+ width = scr_width;
+ height = ((int)rint(width / aspect_ratio)) & ~1;
+ }
+ x = (scr_width - width) / 2;
+ y = (scr_height - height) / 2;
+ rect->x = scr_xleft + x;
+ rect->y = scr_ytop + y;
+ rect->w = FFMAX(width, 1);
+ rect->h = FFMAX(height, 1);
+}
+
static void video_image_display(VideoState *is)
{
VideoPicture *vp;
SubPicture *sp;
AVPicture pict;
- float aspect_ratio;
- int width, height, x, y;
SDL_Rect rect;
int i;
vp = &is->pictq[is->pictq_rindex];
if (vp->bmp) {
- if (vp->sample_aspect_ratio.num == 0)
- aspect_ratio = 0;
- else
- aspect_ratio = av_q2d(vp->sample_aspect_ratio);
-
- if (aspect_ratio <= 0.0)
- aspect_ratio = 1.0;
- aspect_ratio *= (float)vp->width / (float)vp->height;
-
if (is->subtitle_st) {
if (is->subpq_size > 0) {
sp = &is->subpq[is->subpq_rindex];
}
}
+ calculate_display_rect(&rect, is->xleft, is->ytop, is->width, is->height, vp);
- /* XXX: we suppose the screen has a 1.0 pixel ratio */
- height = is->height;
- width = ((int)rint(height * aspect_ratio)) & ~1;
- if (width > is->width) {
- width = is->width;
- height = ((int)rint(width / aspect_ratio)) & ~1;
- }
- x = (is->width - width) / 2;
- y = (is->height - height) / 2;
- is->no_background = 0;
- rect.x = is->xleft + x;
- rect.y = is->ytop + y;
- rect.w = FFMAX(width, 1);
- rect.h = FFMAX(height, 1);
SDL_DisplayYUVOverlay(vp->bmp, &rect);
}
}
uninit_opts();
#if CONFIG_AVFILTER
avfilter_uninit();
+ av_freep(&vfilters);
#endif
avformat_network_deinit();
if (show_status)
int flags = SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL;
int w,h;
VideoPicture *vp = &is->pictq[is->pictq_rindex];
+ SDL_Rect rect;
if (is_full_screen) flags |= SDL_FULLSCREEN;
else flags |= SDL_RESIZABLE;
w = screen_width;
h = screen_height;
} else if (vp->width) {
- w = vp->width;
- h = vp->height;
+ calculate_display_rect(&rect, 0, 0, INT_MAX, vp->height, vp);
+ w = rect.w;
+ h = rect.h;
} else {
w = 640;
h = 480;
prevvp = &is->pictq[(is->pictq_rindex + VIDEO_PICTURE_QUEUE_SIZE - 1) % VIDEO_PICTURE_QUEUE_SIZE];
if (prevvp->allocated && !prevvp->skip) {
SDL_LockMutex(is->pictq_mutex);
- if (is->pictq_size < VIDEO_PICTURE_QUEUE_SIZE) {
+ if (is->pictq_size < VIDEO_PICTURE_QUEUE_SIZE - 1) {
if (--is->pictq_rindex == -1)
is->pictq_rindex = VIDEO_PICTURE_QUEUE_SIZE - 1;
is->pictq_size++;
SubPicture *sp, *sp2;
if (is->video_st) {
+ if (is->force_refresh)
+ pictq_prev_picture(is);
retry:
if (is->pictq_size == 0) {
SDL_LockMutex(is->pictq_mutex);
/* allocate a picture (needs to do that in main thread to avoid
potential locking problems */
-static void alloc_picture(AllocEventProps *event_props)
+static void alloc_picture(VideoState *is)
{
- VideoState *is = event_props->is;
- AVFrame *frame = event_props->frame;
VideoPicture *vp;
vp = &is->pictq[is->pictq_windex];
avfilter_unref_bufferp(&vp->picref);
#endif
- vp->width = frame->width;
- vp->height = frame->height;
-
- video_open(event_props->is, 0);
+ video_open(is, 0);
vp->bmp = SDL_CreateYUVOverlay(vp->width, vp->height,
SDL_YV12_OVERLAY,
SDL_LockMutex(is->pictq_mutex);
/* keep the last already displayed picture in the queue */
- while (is->pictq_size >= VIDEO_PICTURE_QUEUE_SIZE - 1 &&
+ while (is->pictq_size >= VIDEO_PICTURE_QUEUE_SIZE - 2 &&
!is->videoq.abort_request) {
SDL_CondWait(is->pictq_cond, is->pictq_mutex);
}
vp = &is->pictq[is->pictq_windex];
+#if CONFIG_AVFILTER
+ vp->sample_aspect_ratio = ((AVFilterBufferRef *)src_frame->opaque)->video->sample_aspect_ratio;
+#else
+ vp->sample_aspect_ratio = av_guess_sample_aspect_ratio(is->ic, is->video_st, src_frame);
+#endif
+
/* alloc or resize hardware picture buffer */
- if (!vp->bmp || vp->reallocate ||
+ if (!vp->bmp || vp->reallocate || !vp->allocated ||
vp->width != src_frame->width ||
vp->height != src_frame->height) {
SDL_Event event;
- AllocEventProps event_props;
-
- event_props.frame = src_frame;
- event_props.is = is;
vp->allocated = 0;
vp->reallocate = 0;
+ vp->width = src_frame->width;
+ vp->height = src_frame->height;
/* the allocation must be done in the main thread to avoid
- locking problems. We wait in this block for the event to complete,
- so we can pass a pointer to event_props to it. */
+ locking problems. */
event.type = FF_ALLOC_EVENT;
- event.user.data1 = &event_props;
+ event.user.data1 = is;
SDL_PushEvent(&event);
/* wait until the picture is allocated */
// FIXME use direct rendering
av_picture_copy(&pict, (AVPicture *)src_frame,
src_frame->format, vp->width, vp->height);
- vp->sample_aspect_ratio = vp->picref->video->sample_aspect_ratio;
#else
sws_flags = av_get_int(sws_opts, "sws_flags", NULL);
is->img_convert_ctx = sws_getCachedContext(is->img_convert_ctx,
}
sws_scale(is->img_convert_ctx, src_frame->data, src_frame->linesize,
0, vp->height, pict.data, pict.linesize);
- vp->sample_aspect_ratio = av_guess_sample_aspect_ratio(is->ic, is->video_st, src_frame);
#endif
/* update the bitmap content */
SDL_UnlockYUVOverlay(vp->bmp);
buffersink_params->pixel_fmts = pix_fmts;
ret = avfilter_graph_create_filter(&filt_out,
- avfilter_get_by_name("buffersink"),
+ avfilter_get_by_name("ffbuffersink"),
"ffplay_buffersink", NULL, buffersink_params, graph);
av_freep(&buffersink_params);
if (ret < 0)
the_end:
avcodec_flush_buffers(is->video_st->codec);
#if CONFIG_AVFILTER
- av_freep(&vfilters);
avfilter_graph_free(&graph);
#endif
av_free_packet(&pkt);
- av_free(frame);
+ avcodec_free_frame(&frame);
return 0;
}
avcodec_decode_subtitle2(is->subtitle_st->codec, &sp->sub,
&got_subtitle, pkt);
-
if (got_subtitle && sp->sub.format == 0) {
+ if (sp->sub.pts != AV_NOPTS_VALUE)
+ pts = sp->sub.pts / (double)AV_TIME_BASE;
sp->pts = pts;
for (i = 0; i < sp->sub.num_rects; i++)
swr_free(&is->swr_ctx);
av_freep(&is->audio_buf1);
is->audio_buf = NULL;
- av_freep(&is->frame);
+ avcodec_free_frame(&is->frame);
if (is->rdft) {
av_rdft_end(is->rdft);
return is->abort_request;
}
+static int is_realtime(AVFormatContext *s)
+{
+ if( !strcmp(s->iformat->name, "rtp")
+ || !strcmp(s->iformat->name, "rtsp")
+ || !strcmp(s->iformat->name, "sdp")
+ )
+ return 1;
+
+ if(s->pb && ( !strncmp(s->filename, "rtp:", 4)
+ || !strncmp(s->filename, "udp:", 4)
+ )
+ )
+ return 1;
+ return 0;
+}
+
/* this thread gets the stream from the disk or the network */
static int read_thread(void *arg)
{
goto fail;
}
+ if (infinite_buffer < 0 && is_realtime(ic))
+ infinite_buffer = 1;
+
for (;;) {
if (is->abort_request)
break;
}
/* if the queue are full, no need to read more */
- if (!infinite_buffer &&
+ if (infinite_buffer<1 &&
(is->audioq.size + is->videoq.size + is->subtitleq.size > MAX_QUEUE_SIZE
|| ( (is->audioq .nb_packets > MIN_FRAMES || is->audio_stream < 0 || is->audioq.abort_request)
&& (is->videoq .nb_packets > MIN_FRAMES || is->video_stream < 0 || is->videoq.abort_request)
eof = 1;
if (ic->pb && ic->pb->error)
break;
- SDL_Delay(100); /* wait for user event */
+ SDL_LockMutex(wait_mutex);
+ SDL_CondWaitTimeout(is->continue_read_thread, wait_mutex, 10);
+ SDL_UnlockMutex(wait_mutex);
continue;
}
/* check if packet is in play range specified by user, then queue, otherwise discard */
alloc_picture(event.user.data1);
break;
case FF_REFRESH_EVENT:
- if (cur_stream->force_refresh)
- pictq_prev_picture(event.user.data1);
video_refresh(event.user.data1);
cur_stream->refresh = 0;
break;
if (input_filename) {
fprintf(stderr, "Argument '%s' provided as input filename, but '%s' was already specified.\n",
filename, input_filename);
- exit_program(1);
+ exit(1);
}
if (!strcmp(filename, "-"))
filename = "pipe:";