#include "libavutil/parseutils.h"
#include "libavutil/samplefmt.h"
#include "libavutil/avassert.h"
+#include "libavutil/time.h"
#include "libavformat/avformat.h"
#include "libavdevice/avdevice.h"
#include "libswscale/swscale.h"
# include "libavfilter/avfilter.h"
# include "libavfilter/avfiltergraph.h"
# include "libavfilter/buffersink.h"
+# include "libavfilter/buffersrc.h"
#endif
#include <SDL.h>
#include "cmdutils.h"
-#include <unistd.h>
#include <assert.h>
const char program_name[] = "ffplay";
typedef struct VideoPicture {
double pts; ///< presentation time stamp for this picture
- double duration; ///< expected duration of the frame
int64_t pos; ///< byte position in file
int skip;
SDL_Overlay *bmp;
AVRational sample_aspect_ratio;
int allocated;
int reallocate;
- enum PixelFormat pix_fmt;
#if CONFIG_AVFILTER
AVFilterBufferRef *picref;
AVSubtitle sub;
} SubPicture;
+typedef struct AudioParams {
+ int freq;
+ int channels;
+ int channel_layout;
+ enum AVSampleFormat fmt;
+} AudioParams;
+
enum {
AV_SYNC_AUDIO_MASTER, /* default choice */
AV_SYNC_VIDEO_MASTER,
int audio_write_buf_size;
AVPacket audio_pkt_temp;
AVPacket audio_pkt;
- enum AVSampleFormat audio_src_fmt;
- enum AVSampleFormat audio_tgt_fmt;
- int audio_src_channels;
- int audio_tgt_channels;
- int64_t audio_src_channel_layout;
- int64_t audio_tgt_channel_layout;
- int audio_src_freq;
- int audio_tgt_freq;
+ struct AudioParams audio_src;
+ struct AudioParams audio_tgt;
struct SwrContext *swr_ctx;
double audio_current_pts;
double audio_current_pts_drift;
int step;
#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
int refresh;
static int exit_on_mousedown;
static int loop = 1;
static int framedrop = -1;
+static int infinite_buffer = 0;
static enum ShowMode show_mode = SHOW_MODE_NONE;
static const char *audio_codec_name;
static const char *subtitle_codec_name;
nb_freq = 1 << (rdft_bits - 1);
/* compute display index : center on currently output samples */
- channels = s->audio_tgt_channels;
+ channels = s->audio_tgt.channels;
nb_display_channels = channels;
if (!s->paused) {
int data_used= s->show_mode == SHOW_MODE_WAVES ? s->width : (2*nb_freq);
the last buffer computation */
if (audio_callback_time) {
time_diff = av_gettime() - audio_callback_time;
- delay -= (time_diff * s->audio_tgt_freq) / 1000000;
+ delay -= (time_diff * s->audio_tgt.freq) / 1000000;
}
delay += 2 * data_used;
for (i = 0; i < VIDEO_PICTURE_QUEUE_SIZE; i++) {
vp = &is->pictq[i];
#if CONFIG_AVFILTER
- if (vp->picref) {
- avfilter_unref_buffer(vp->picref);
- vp->picref = NULL;
- }
+ avfilter_unref_bufferp(&vp->picref);
#endif
if (vp->bmp) {
SDL_FreeYUVOverlay(vp->bmp);
SDL_PushEvent(&event);
}
//FIXME ideally we should wait the correct time but SDLs event passing is so slow it would be silly
- usleep(is->audio_st && is->show_mode != SHOW_MODE_VIDEO ? rdftspeed*1000 : 5000);
+ av_usleep(is->audio_st && is->show_mode != SHOW_MODE_VIDEO ? rdftspeed*1000 : 5000);
}
return 0;
}
if (is->pictq_size > 1) {
VideoPicture *nextvp = &is->pictq[(is->pictq_rindex + 1) % VIDEO_PICTURE_QUEUE_SIZE];
- duration = nextvp->pts - vp->pts; // More accurate this way, 1/time_base is often not reflecting FPS
- } else {
- duration = vp->duration;
- }
-
- if((framedrop>0 || (framedrop && is->audio_st)) && time > is->frame_timer + duration){
- if(is->pictq_size > 1){
+ duration = nextvp->pts - vp->pts;
+ if((framedrop>0 || (framedrop && is->audio_st)) && time > is->frame_timer + duration){
is->frame_drops_late++;
pictq_next_picture(is);
goto retry;
SDL_FreeYUVOverlay(vp->bmp);
#if CONFIG_AVFILTER
- if (vp->picref)
- avfilter_unref_buffer(vp->picref);
- vp->picref = NULL;
+ avfilter_unref_bufferp(&vp->picref);
#endif
vp->width = frame->width;
vp->height = frame->height;
- vp->pix_fmt = frame->format;
video_open(event_props->is, 0);
vp = &is->pictq[is->pictq_windex];
- vp->duration = frame_delay;
-
/* alloc or resize hardware picture buffer */
if (!vp->bmp || vp->reallocate ||
vp->width != src_frame->width ||
if (vp->bmp) {
AVPicture pict = { { 0 } };
#if CONFIG_AVFILTER
- if (vp->picref)
- avfilter_unref_buffer(vp->picref);
+ avfilter_unref_bufferp(&vp->picref);
vp->picref = src_frame->opaque;
#endif
#if CONFIG_AVFILTER
// FIXME use direct rendering
av_picture_copy(&pict, (AVPicture *)src_frame,
- vp->pix_fmt, vp->width, vp->height);
+ 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,
- vp->width, vp->height, vp->pix_fmt, vp->width, vp->height,
+ vp->width, vp->height, src_frame->format, vp->width, vp->height,
PIX_FMT_YUV420P, sws_flags, NULL, NULL, NULL);
if (is->img_convert_ctx == NULL) {
fprintf(stderr, "Cannot initialize the conversion context\n");
return 0;
}
- avcodec_decode_video2(is->video_st->codec, frame, &got_picture, pkt);
+ if(avcodec_decode_video2(is->video_st->codec, frame, &got_picture, pkt) < 0)
+ return 0;
if (got_picture) {
int ret = 1;
SDL_UnlockMutex(is->pictq_mutex);
}
- if (ret)
- is->frame_last_returned_time = av_gettime() / 1000000.0;
-
return ret;
}
return 0;
}
#if CONFIG_AVFILTER
-typedef struct {
- VideoState *is;
- AVFrame *frame;
- int use_dr1;
-} FilterPriv;
-
-static int input_get_buffer(AVCodecContext *codec, AVFrame *pic)
+static int configure_filtergraph(AVFilterGraph *graph, const char *filtergraph,
+ AVFilterContext *source_ctx, AVFilterContext *sink_ctx)
{
- AVFilterContext *ctx = codec->opaque;
- AVFilterBufferRef *ref;
- int perms = AV_PERM_WRITE;
- int i, w, h, stride[AV_NUM_DATA_POINTERS];
- unsigned edge;
- int pixel_size;
-
- av_assert0(codec->flags & CODEC_FLAG_EMU_EDGE);
-
- if (codec->codec->capabilities & CODEC_CAP_NEG_LINESIZES)
- perms |= AV_PERM_NEG_LINESIZES;
-
- if (pic->buffer_hints & FF_BUFFER_HINTS_VALID) {
- if (pic->buffer_hints & FF_BUFFER_HINTS_READABLE) perms |= AV_PERM_READ;
- if (pic->buffer_hints & FF_BUFFER_HINTS_PRESERVE) perms |= AV_PERM_PRESERVE;
- if (pic->buffer_hints & FF_BUFFER_HINTS_REUSABLE) perms |= AV_PERM_REUSE2;
- }
- if (pic->reference) perms |= AV_PERM_READ | AV_PERM_PRESERVE;
-
- w = codec->width;
- h = codec->height;
-
- if(av_image_check_size(w, h, 0, codec) || codec->pix_fmt<0)
- return -1;
-
- avcodec_align_dimensions2(codec, &w, &h, stride);
- edge = codec->flags & CODEC_FLAG_EMU_EDGE ? 0 : avcodec_get_edge_width();
- w += edge << 1;
- h += edge << 1;
- if (codec->pix_fmt != ctx->outputs[0]->format) {
- av_log(codec, AV_LOG_ERROR, "Pixel format mismatches %d %d\n", codec->pix_fmt, ctx->outputs[0]->format);
- return -1;
- }
- if (!(ref = avfilter_get_video_buffer(ctx->outputs[0], perms, w, h)))
- return -1;
-
- pixel_size = av_pix_fmt_descriptors[ref->format].comp[0].step_minus1 + 1;
- ref->video->w = codec->width;
- ref->video->h = codec->height;
- for (i = 0; i < 4; i ++) {
- unsigned hshift = (i == 1 || i == 2) ? av_pix_fmt_descriptors[ref->format].log2_chroma_w : 0;
- unsigned vshift = (i == 1 || i == 2) ? av_pix_fmt_descriptors[ref->format].log2_chroma_h : 0;
+ int ret;
+ AVFilterInOut *outputs = NULL, *inputs = NULL;
- pic->base[i] = ref->data[i];
- if (ref->data[i]) {
- ref->data[i] += ((edge * pixel_size) >> hshift) + ((edge * ref->linesize[i]) >> vshift);
+ if (filtergraph) {
+ outputs = avfilter_inout_alloc();
+ inputs = avfilter_inout_alloc();
+ if (!outputs || !inputs) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
}
- pic->data[i] = ref->data[i];
- pic->linesize[i] = ref->linesize[i];
- }
- pic->opaque = ref;
- pic->type = FF_BUFFER_TYPE_USER;
- pic->reordered_opaque = codec->reordered_opaque;
- pic->width = codec->width;
- pic->height = codec->height;
- pic->format = codec->pix_fmt;
- pic->sample_aspect_ratio = codec->sample_aspect_ratio;
- if (codec->pkt) pic->pkt_pts = codec->pkt->pts;
- else pic->pkt_pts = AV_NOPTS_VALUE;
- return 0;
-}
-static void input_release_buffer(AVCodecContext *codec, AVFrame *pic)
-{
- memset(pic->data, 0, sizeof(pic->data));
- avfilter_unref_buffer(pic->opaque);
-}
+ outputs->name = av_strdup("in");
+ outputs->filter_ctx = source_ctx;
+ outputs->pad_idx = 0;
+ outputs->next = NULL;
-static int input_reget_buffer(AVCodecContext *codec, AVFrame *pic)
-{
- AVFilterBufferRef *ref = pic->opaque;
+ inputs->name = av_strdup("out");
+ inputs->filter_ctx = sink_ctx;
+ inputs->pad_idx = 0;
+ inputs->next = NULL;
- if (pic->data[0] == NULL) {
- pic->buffer_hints |= FF_BUFFER_HINTS_READABLE;
- return codec->get_buffer(codec, pic);
- }
-
- if ((codec->width != ref->video->w) || (codec->height != ref->video->h) ||
- (codec->pix_fmt != ref->format)) {
- av_log(codec, AV_LOG_ERROR, "Picture properties changed.\n");
- return -1;
- }
-
- pic->reordered_opaque = codec->reordered_opaque;
- if (codec->pkt) pic->pkt_pts = codec->pkt->pts;
- else pic->pkt_pts = AV_NOPTS_VALUE;
- return 0;
-}
-
-static int input_init(AVFilterContext *ctx, const char *args, void *opaque)
-{
- FilterPriv *priv = ctx->priv;
- AVCodecContext *codec;
- if (!opaque) return -1;
-
- priv->is = opaque;
- codec = priv->is->video_st->codec;
- codec->opaque = ctx;
- if (codec->codec->capabilities & CODEC_CAP_DR1) {
- av_assert0(codec->flags & CODEC_FLAG_EMU_EDGE);
- priv->use_dr1 = 1;
- codec->get_buffer = input_get_buffer;
- codec->release_buffer = input_release_buffer;
- codec->reget_buffer = input_reget_buffer;
- codec->thread_safe_callbacks = 1;
- }
-
- priv->frame = avcodec_alloc_frame();
-
- return 0;
-}
-
-static void input_uninit(AVFilterContext *ctx)
-{
- FilterPriv *priv = ctx->priv;
- av_free(priv->frame);
-}
-
-static int input_request_frame(AVFilterLink *link)
-{
- FilterPriv *priv = link->src->priv;
- AVFilterBufferRef *picref;
- int64_t pts = 0;
- AVPacket pkt;
- int ret;
-
- while (!(ret = get_video_frame(priv->is, priv->frame, &pts, &pkt)))
- av_free_packet(&pkt);
- if (ret < 0)
- return -1;
-
- if (priv->use_dr1 && priv->frame->opaque) {
- picref = avfilter_ref_buffer(priv->frame->opaque, ~0);
+ if ((ret = avfilter_graph_parse(graph, filtergraph, &inputs, &outputs, NULL)) < 0)
+ goto fail;
} else {
- picref = avfilter_get_video_buffer(link, AV_PERM_WRITE, priv->frame->width, priv->frame->height);
- av_image_copy(picref->data, picref->linesize,
- (const uint8_t **)(void **)priv->frame->data, priv->frame->linesize,
- picref->format, priv->frame->width, priv->frame->height);
+ if ((ret = avfilter_link(source_ctx, 0, sink_ctx, 0)) < 0)
+ goto fail;
}
- av_free_packet(&pkt);
-
- avfilter_copy_frame_props(picref, priv->frame);
- picref->video->sample_aspect_ratio = av_guess_sample_aspect_ratio(priv->is->ic, priv->is->video_st, priv->frame);
- picref->pts = pts;
-
- avfilter_start_frame(link, picref);
- avfilter_draw_slice(link, 0, picref->video->h, 1);
- avfilter_end_frame(link);
- return 0;
-}
-
-static int input_query_formats(AVFilterContext *ctx)
-{
- FilterPriv *priv = ctx->priv;
- enum PixelFormat pix_fmts[] = {
- priv->is->video_st->codec->pix_fmt, PIX_FMT_NONE
- };
-
- avfilter_set_common_pixel_formats(ctx, avfilter_make_format_list(pix_fmts));
- return 0;
-}
-
-static int input_config_props(AVFilterLink *link)
-{
- FilterPriv *priv = link->src->priv;
- AVStream *s = priv->is->video_st;
-
- link->w = s->codec->width;
- link->h = s->codec->height;
- link->sample_aspect_ratio = s->sample_aspect_ratio.num ?
- s->sample_aspect_ratio : s->codec->sample_aspect_ratio;
- link->time_base = s->time_base;
-
- return 0;
+ return avfilter_graph_config(graph, NULL);
+fail:
+ avfilter_inout_free(&outputs);
+ avfilter_inout_free(&inputs);
+ return ret;
}
-static AVFilter input_filter =
-{
- .name = "ffplay_input",
-
- .priv_size = sizeof(FilterPriv),
-
- .init = input_init,
- .uninit = input_uninit,
-
- .query_formats = input_query_formats,
-
- .inputs = (AVFilterPad[]) {{ .name = NULL }},
- .outputs = (AVFilterPad[]) {{ .name = "default",
- .type = AVMEDIA_TYPE_VIDEO,
- .request_frame = input_request_frame,
- .config_props = input_config_props, },
- { .name = NULL }},
-};
-
static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const char *vfilters)
{
static const enum PixelFormat pix_fmts[] = { PIX_FMT_YUV420P, PIX_FMT_NONE };
char sws_flags_str[128];
+ char buffersrc_args[256];
int ret;
AVBufferSinkParams *buffersink_params = av_buffersink_params_alloc();
- AVFilterContext *filt_src = NULL, *filt_out = NULL, *filt_format;;
+ AVFilterContext *filt_src = NULL, *filt_out = NULL, *filt_format;
+ AVCodecContext *codec = is->video_st->codec;
+
snprintf(sws_flags_str, sizeof(sws_flags_str), "flags=%d", sws_flags);
graph->scale_sws_opts = av_strdup(sws_flags_str);
- if ((ret = avfilter_graph_create_filter(&filt_src, &input_filter, "src",
- NULL, is, graph)) < 0)
+ snprintf(buffersrc_args, sizeof(buffersrc_args),
+ "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
+ codec->width, codec->height, codec->pix_fmt,
+ is->video_st->time_base.num, is->video_st->time_base.den,
+ codec->sample_aspect_ratio.num, codec->sample_aspect_ratio.den);
+
+ if ((ret = avfilter_graph_create_filter(&filt_src,
+ avfilter_get_by_name("buffer"),
+ "ffplay_buffer", buffersrc_args, NULL,
+ graph)) < 0)
return ret;
-#if FF_API_OLD_VSINK_API
- ret = avfilter_graph_create_filter(&filt_out,
- avfilter_get_by_name("buffersink"),
- "out", NULL, pix_fmts, graph);
-#else
buffersink_params->pixel_fmts = pix_fmts;
ret = avfilter_graph_create_filter(&filt_out,
avfilter_get_by_name("buffersink"),
- "out", NULL, buffersink_params, graph);
-#endif
+ "ffplay_buffersink", NULL, buffersink_params, graph);
av_freep(&buffersink_params);
if (ret < 0)
return ret;
if ((ret = avfilter_link(filt_format, 0, filt_out, 0)) < 0)
return ret;
-
- if (vfilters) {
- AVFilterInOut *outputs = avfilter_inout_alloc();
- AVFilterInOut *inputs = avfilter_inout_alloc();
-
- outputs->name = av_strdup("in");
- outputs->filter_ctx = filt_src;
- outputs->pad_idx = 0;
- outputs->next = NULL;
-
- inputs->name = av_strdup("out");
- inputs->filter_ctx = filt_format;
- 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)
- return ret;
- }
-
- if ((ret = avfilter_graph_config(graph, NULL)) < 0)
+ if ((ret = configure_filtergraph(graph, vfilters, filt_src, filt_format)) < 0)
return ret;
+ is->in_video_filter = filt_src;
is->out_video_filter = filt_out;
return ret;
static int video_thread(void *arg)
{
+ AVPacket pkt = { 0 };
VideoState *is = arg;
AVFrame *frame = avcodec_alloc_frame();
int64_t pts_int = AV_NOPTS_VALUE, pos = -1;
int ret;
#if CONFIG_AVFILTER
+ AVCodecContext *codec = is->video_st->codec;
AVFilterGraph *graph = avfilter_graph_alloc();
- AVFilterContext *filt_out = NULL;
- int last_w = is->video_st->codec->width;
- int last_h = is->video_st->codec->height;
+ AVFilterContext *filt_out = NULL, *filt_in = NULL;
+ int last_w = 0;
+ int last_h = 0;
+ enum PixelFormat last_format = -2;
- if ((ret = configure_video_filters(graph, is, vfilters)) < 0) {
- SDL_Event event;
- event.type = FF_QUIT_EVENT;
- event.user.data1 = is;
- SDL_PushEvent(&event);
- goto the_end;
+ 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;
}
- filt_out = is->out_video_filter;
#endif
for (;;) {
-#if !CONFIG_AVFILTER
- AVPacket pkt;
-#else
+#if CONFIG_AVFILTER
AVFilterBufferRef *picref;
- AVRational tb = filt_out->inputs[0]->time_base;
+ AVRational tb;
#endif
while (is->paused && !is->videoq.abort_request)
SDL_Delay(10);
+
+ avcodec_get_frame_defaults(frame);
+ av_free_packet(&pkt);
+
+ ret = get_video_frame(is, frame, &pts_int, &pkt);
+ if (ret < 0)
+ goto the_end;
+
+ if (!ret)
+ continue;
+
#if CONFIG_AVFILTER
if ( last_w != is->video_st->codec->width
- || last_h != is->video_st->codec->height) {
+ || last_h != is->video_st->codec->height
+ || last_format != is->video_st->codec->pix_fmt) {
av_log(NULL, AV_LOG_INFO, "Frame changed from size:%dx%d to size:%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();
- if ((ret = configure_video_filters(graph, is, vfilters)) < 0)
+ if ((ret = configure_video_filters(graph, is, vfilters)) < 0) {
+ SDL_Event event;
+ event.type = FF_QUIT_EVENT;
+ event.user.data1 = is;
+ SDL_PushEvent(&event);
+ av_free_packet(&pkt);
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_format = is->video_st->codec->pix_fmt;
}
- ret = av_buffersink_get_buffer_ref(filt_out, &picref, 0);
- if (picref) {
- avfilter_fill_frame_from_video_buffer_ref(frame, picref);
- pts_int = picref->pts;
- tb = filt_out->inputs[0]->time_base;
- pos = picref->pos;
- frame->opaque = picref;
- ret = 1;
- }
+ frame->pts = pts_int;
+ frame->sample_aspect_ratio = av_guess_sample_aspect_ratio(is->ic, is->video_st, frame);
+ if (is->use_dr1 && frame->opaque) {
+ 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_add_ref(filt_in, fb, AV_BUFFERSRC_FLAG_NO_COPY);
+
+ } else
+ av_buffersrc_write_frame(filt_in, frame);
- if (ret >= 0 && 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(): "
- "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);
- }
-#else
- ret = get_video_frame(is, frame, &pts_int, &pkt);
- pos = pkt.pos;
av_free_packet(&pkt);
- if (ret == 0)
- continue;
-#endif
- if (ret < 0)
- goto the_end;
+ while (ret >= 0) {
+ is->frame_last_returned_time = av_gettime() / 1000000.0;
- is->frame_last_filter_delay = av_gettime() / 1000000.0 - is->frame_last_returned_time;
- if (fabs(is->frame_last_filter_delay) > AV_NOSYNC_THRESHOLD / 10.0)
- is->frame_last_filter_delay = 0;
+ ret = av_buffersink_get_buffer_ref(filt_out, &picref, 0);
+ if (ret < 0) {
+ ret = 0;
+ break;
+ }
-#if CONFIG_AVFILTER
- if (!picref)
- continue;
-#endif
+ is->frame_last_filter_delay = av_gettime() / 1000000.0 - is->frame_last_returned_time;
+ if (fabs(is->frame_last_filter_delay) > AV_NOSYNC_THRESHOLD / 10.0)
+ is->frame_last_filter_delay = 0;
- pts = pts_int * av_q2d(is->video_st->time_base);
+ avfilter_copy_buf_props(frame, picref);
+
+ pts_int = picref->pts;
+ tb = filt_out->inputs[0]->time_base;
+ pos = picref->pos;
+ frame->opaque = picref;
- ret = queue_picture(is, frame, pts, pos);
+ 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(): "
+ "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 = queue_picture(is, frame, pts, pos);
+ }
+#else
+ pts = pts_int * av_q2d(is->video_st->time_base);
+ ret = queue_picture(is, frame, pts, pkt.pos);
+#endif
if (ret < 0)
goto the_end;
av_freep(&vfilters);
avfilter_graph_free(&graph);
#endif
+ av_free_packet(&pkt);
av_free(frame);
return 0;
}
avg_diff = is->audio_diff_cum * (1.0 - is->audio_diff_avg_coef);
if (fabs(avg_diff) >= is->audio_diff_threshold) {
- wanted_nb_samples = nb_samples + (int)(diff * is->audio_src_freq);
+ wanted_nb_samples = nb_samples + (int)(diff * is->audio_src.freq);
min_nb_samples = ((nb_samples * (100 - SAMPLE_CORRECTION_PERCENT_MAX) / 100));
max_nb_samples = ((nb_samples * (100 + SAMPLE_CORRECTION_PERCENT_MAX) / 100));
wanted_nb_samples = FFMIN(FFMAX(wanted_nb_samples, min_nb_samples), max_nb_samples);
} else
avcodec_get_frame_defaults(is->frame);
+ if (is->paused)
+ return -1;
+
if (flush_complete)
break;
new_packet = 0;
is->frame->nb_samples,
dec->sample_fmt, 1);
- dec_channel_layout = (dec->channel_layout && dec->channels == av_get_channel_layout_nb_channels(dec->channel_layout)) ? dec->channel_layout : av_get_default_channel_layout(dec->channels);
+ dec_channel_layout =
+ (dec->channel_layout && dec->channels == av_get_channel_layout_nb_channels(dec->channel_layout)) ?
+ dec->channel_layout : av_get_default_channel_layout(dec->channels);
wanted_nb_samples = synchronize_audio(is, is->frame->nb_samples);
- if (dec->sample_fmt != is->audio_src_fmt ||
- dec_channel_layout != is->audio_src_channel_layout ||
- dec->sample_rate != is->audio_src_freq ||
+ if (dec->sample_fmt != is->audio_src.fmt ||
+ dec_channel_layout != is->audio_src.channel_layout ||
+ dec->sample_rate != is->audio_src.freq ||
(wanted_nb_samples != is->frame->nb_samples && !is->swr_ctx)) {
- if (is->swr_ctx)
- swr_free(&is->swr_ctx);
+ swr_free(&is->swr_ctx);
is->swr_ctx = swr_alloc_set_opts(NULL,
- is->audio_tgt_channel_layout, is->audio_tgt_fmt, is->audio_tgt_freq,
+ is->audio_tgt.channel_layout, is->audio_tgt.fmt, is->audio_tgt.freq,
dec_channel_layout, dec->sample_fmt, dec->sample_rate,
0, NULL);
if (!is->swr_ctx || swr_init(is->swr_ctx) < 0) {
fprintf(stderr, "Cannot create sample rate converter for conversion of %d Hz %s %d channels to %d Hz %s %d channels!\n",
- dec->sample_rate,
- av_get_sample_fmt_name(dec->sample_fmt),
- dec->channels,
- is->audio_tgt_freq,
- av_get_sample_fmt_name(is->audio_tgt_fmt),
- is->audio_tgt_channels);
+ dec->sample_rate, av_get_sample_fmt_name(dec->sample_fmt), dec->channels,
+ is->audio_tgt.freq, av_get_sample_fmt_name(is->audio_tgt.fmt), is->audio_tgt.channels);
break;
}
- is->audio_src_channel_layout = dec_channel_layout;
- is->audio_src_channels = dec->channels;
- is->audio_src_freq = dec->sample_rate;
- is->audio_src_fmt = dec->sample_fmt;
+ is->audio_src.channel_layout = dec_channel_layout;
+ is->audio_src.channels = dec->channels;
+ is->audio_src.freq = dec->sample_rate;
+ is->audio_src.fmt = dec->sample_fmt;
}
- resampled_data_size = data_size;
if (is->swr_ctx) {
const uint8_t *in[] = { is->frame->data[0] };
uint8_t *out[] = {is->audio_buf2};
+ int out_count = sizeof(is->audio_buf2) / is->audio_tgt.channels / av_get_bytes_per_sample(is->audio_tgt.fmt);
if (wanted_nb_samples != is->frame->nb_samples) {
- if (swr_set_compensation(is->swr_ctx, (wanted_nb_samples - is->frame->nb_samples) * is->audio_tgt_freq / dec->sample_rate,
- wanted_nb_samples * is->audio_tgt_freq / dec->sample_rate) < 0) {
+ if (swr_set_compensation(is->swr_ctx, (wanted_nb_samples - is->frame->nb_samples) * is->audio_tgt.freq / dec->sample_rate,
+ wanted_nb_samples * is->audio_tgt.freq / dec->sample_rate) < 0) {
fprintf(stderr, "swr_set_compensation() failed\n");
break;
}
}
- len2 = swr_convert(is->swr_ctx, out, sizeof(is->audio_buf2) / is->audio_tgt_channels / av_get_bytes_per_sample(is->audio_tgt_fmt),
- in, is->frame->nb_samples);
+ len2 = swr_convert(is->swr_ctx, out, out_count, in, is->frame->nb_samples);
if (len2 < 0) {
- fprintf(stderr, "audio_resample() failed\n");
+ fprintf(stderr, "swr_convert() failed\n");
break;
}
- if (len2 == sizeof(is->audio_buf2) / is->audio_tgt_channels / av_get_bytes_per_sample(is->audio_tgt_fmt)) {
+ if (len2 == out_count) {
fprintf(stderr, "warning: audio buffer is probably too small\n");
swr_init(is->swr_ctx);
}
is->audio_buf = is->audio_buf2;
- resampled_data_size = len2 * is->audio_tgt_channels * av_get_bytes_per_sample(is->audio_tgt_fmt);
+ resampled_data_size = len2 * is->audio_tgt.channels * av_get_bytes_per_sample(is->audio_tgt.fmt);
} else {
is->audio_buf = is->frame->data[0];
+ resampled_data_size = data_size;
}
/* if no pts, then compute it */
VideoState *is = opaque;
int audio_size, len1;
int bytes_per_sec;
- int frame_size = av_samples_get_buffer_size(NULL, is->audio_tgt_channels, 1, is->audio_tgt_fmt, 1);
+ int frame_size = av_samples_get_buffer_size(NULL, is->audio_tgt.channels, 1, is->audio_tgt.fmt, 1);
double pts;
audio_callback_time = av_gettime();
stream += len1;
is->audio_buf_index += len1;
}
- bytes_per_sec = is->audio_tgt_freq * is->audio_tgt_channels * av_get_bytes_per_sample(is->audio_tgt_fmt);
+ bytes_per_sec = is->audio_tgt.freq * is->audio_tgt.channels * av_get_bytes_per_sample(is->audio_tgt.fmt);
is->audio_write_buf_size = is->audio_buf_size - is->audio_buf_index;
/* Let's assume the audio driver that is used by SDL has two periods. */
is->audio_current_pts = is->audio_clock - (double)(2 * is->audio_hw_buf_size + is->audio_write_buf_size) / bytes_per_sec;
is->audio_current_pts_drift = is->audio_current_pts - audio_callback_time / 1000000.0;
}
+static int audio_open(void *opaque, int64_t wanted_channel_layout, int wanted_nb_channels, int wanted_sample_rate, struct AudioParams *audio_hw_params)
+{
+ SDL_AudioSpec wanted_spec, spec;
+ const char *env;
+ const int next_nb_channels[] = {0, 0, 1, 6, 2, 6, 4, 6};
+
+ env = SDL_getenv("SDL_AUDIO_CHANNELS");
+ if (env) {
+ wanted_nb_channels = SDL_atoi(env);
+ wanted_channel_layout = av_get_default_channel_layout(wanted_nb_channels);
+ }
+ if (!wanted_channel_layout || wanted_nb_channels != av_get_channel_layout_nb_channels(wanted_channel_layout)) {
+ wanted_channel_layout = av_get_default_channel_layout(wanted_nb_channels);
+ wanted_channel_layout &= ~AV_CH_LAYOUT_STEREO_DOWNMIX;
+ }
+ wanted_spec.channels = av_get_channel_layout_nb_channels(wanted_channel_layout);
+ wanted_spec.freq = wanted_sample_rate;
+ if (wanted_spec.freq <= 0 || wanted_spec.channels <= 0) {
+ fprintf(stderr, "Invalid sample rate or channel count!\n");
+ return -1;
+ }
+ wanted_spec.format = AUDIO_S16SYS;
+ wanted_spec.silence = 0;
+ wanted_spec.samples = SDL_AUDIO_BUFFER_SIZE;
+ wanted_spec.callback = sdl_audio_callback;
+ wanted_spec.userdata = opaque;
+ while (SDL_OpenAudio(&wanted_spec, &spec) < 0) {
+ fprintf(stderr, "SDL_OpenAudio (%d channels): %s\n", wanted_spec.channels, SDL_GetError());
+ wanted_spec.channels = next_nb_channels[FFMIN(7, wanted_spec.channels)];
+ if (!wanted_spec.channels) {
+ fprintf(stderr, "No more channel combinations to try, audio open failed\n");
+ return -1;
+ }
+ wanted_channel_layout = av_get_default_channel_layout(wanted_spec.channels);
+ }
+ if (spec.format != AUDIO_S16SYS) {
+ fprintf(stderr, "SDL advised audio format %d is not supported!\n", spec.format);
+ return -1;
+ }
+ if (spec.channels != wanted_spec.channels) {
+ wanted_channel_layout = av_get_default_channel_layout(spec.channels);
+ if (!wanted_channel_layout) {
+ fprintf(stderr, "SDL advised channel count %d is not supported!\n", spec.channels);
+ return -1;
+ }
+ }
+
+ audio_hw_params->fmt = AV_SAMPLE_FMT_S16;
+ audio_hw_params->freq = spec.freq;
+ audio_hw_params->channel_layout = wanted_channel_layout;
+ audio_hw_params->channels = spec.channels;
+ return spec.size;
+}
+
/* open a given stream. Return 0 if OK */
static int stream_component_open(VideoState *is, int stream_index)
{
AVFormatContext *ic = is->ic;
AVCodecContext *avctx;
AVCodec *codec;
- SDL_AudioSpec wanted_spec, spec;
AVDictionary *opts;
AVDictionaryEntry *t = NULL;
- int64_t wanted_channel_layout = 0;
- int wanted_nb_channels;
- const char *env;
if (stream_index < 0 || stream_index >= ic->nb_streams)
return -1;
avctx = ic->streams[stream_index]->codec;
codec = avcodec_find_decoder(avctx->codec_id);
- opts = filter_codec_opts(codec_opts, codec, ic, ic->streams[stream_index]);
+ opts = filter_codec_opts(codec_opts, avctx->codec_id, ic, ic->streams[stream_index], codec);
switch(avctx->codec_type){
case AVMEDIA_TYPE_AUDIO : is->last_audio_stream = stream_index; if(audio_codec_name ) codec= avcodec_find_decoder_by_name( audio_codec_name); break;
if(codec->capabilities & CODEC_CAP_DR1)
avctx->flags |= CODEC_FLAG_EMU_EDGE;
- if (avctx->codec_type == AVMEDIA_TYPE_AUDIO) {
- memset(&is->audio_pkt_temp, 0, sizeof(is->audio_pkt_temp));
- env = SDL_getenv("SDL_AUDIO_CHANNELS");
- if (env)
- wanted_channel_layout = av_get_default_channel_layout(SDL_atoi(env));
- if (!wanted_channel_layout) {
- wanted_channel_layout = (avctx->channel_layout && avctx->channels == av_get_channel_layout_nb_channels(avctx->channel_layout)) ? avctx->channel_layout : av_get_default_channel_layout(avctx->channels);
- wanted_channel_layout &= ~AV_CH_LAYOUT_STEREO_DOWNMIX;
- wanted_nb_channels = av_get_channel_layout_nb_channels(wanted_channel_layout);
- /* SDL only supports 1, 2, 4 or 6 channels at the moment, so we have to make sure not to request anything else. */
- while (wanted_nb_channels > 0 && (wanted_nb_channels == 3 || wanted_nb_channels == 5 || wanted_nb_channels > 6)) {
- wanted_nb_channels--;
- wanted_channel_layout = av_get_default_channel_layout(wanted_nb_channels);
- }
- }
- wanted_spec.channels = av_get_channel_layout_nb_channels(wanted_channel_layout);
- wanted_spec.freq = avctx->sample_rate;
- if (wanted_spec.freq <= 0 || wanted_spec.channels <= 0) {
- fprintf(stderr, "Invalid sample rate or channel count!\n");
- return -1;
- }
- }
-
if (!av_dict_get(opts, "threads", NULL, 0))
av_dict_set(&opts, "threads", "auto", 0);
if (!codec ||
/* prepare audio output */
if (avctx->codec_type == AVMEDIA_TYPE_AUDIO) {
- wanted_spec.format = AUDIO_S16SYS;
- wanted_spec.silence = 0;
- wanted_spec.samples = SDL_AUDIO_BUFFER_SIZE;
- wanted_spec.callback = sdl_audio_callback;
- wanted_spec.userdata = is;
- if (SDL_OpenAudio(&wanted_spec, &spec) < 0) {
- fprintf(stderr, "SDL_OpenAudio: %s\n", SDL_GetError());
- return -1;
- }
- is->audio_hw_buf_size = spec.size;
- if (spec.format != AUDIO_S16SYS) {
- fprintf(stderr, "SDL advised audio format %d is not supported!\n", spec.format);
+ int audio_hw_buf_size = audio_open(is, avctx->channel_layout, avctx->channels, avctx->sample_rate, &is->audio_src);
+ if (audio_hw_buf_size < 0)
return -1;
- }
- if (spec.channels != wanted_spec.channels) {
- wanted_channel_layout = av_get_default_channel_layout(spec.channels);
- if (!wanted_channel_layout) {
- fprintf(stderr, "SDL advised channel count %d is not supported!\n", spec.channels);
- return -1;
- }
- }
- is->audio_src_fmt = is->audio_tgt_fmt = AV_SAMPLE_FMT_S16;
- is->audio_src_freq = is->audio_tgt_freq = spec.freq;
- is->audio_src_channel_layout = is->audio_tgt_channel_layout = wanted_channel_layout;
- is->audio_src_channels = is->audio_tgt_channels = spec.channels;
+ is->audio_hw_buf_size = audio_hw_buf_size;
+ is->audio_tgt = is->audio_src;
}
ic->streams[stream_index]->discard = AVDISCARD_DEFAULT;
is->audio_diff_avg_count = 0;
/* since we do not have a precise anough audio fifo fullness,
we correct audio sync only if larger than this threshold */
- is->audio_diff_threshold = 2.0 * SDL_AUDIO_BUFFER_SIZE / wanted_spec.freq;
+ is->audio_diff_threshold = 2.0 * is->audio_hw_buf_size / av_samples_get_buffer_size(NULL, is->audio_tgt.channels, is->audio_tgt.freq, is->audio_tgt.fmt, 1);
memset(&is->audio_pkt, 0, sizeof(is->audio_pkt));
+ memset(&is->audio_pkt_temp, 0, sizeof(is->audio_pkt_temp));
packet_queue_start(&is->audioq);
SDL_PauseAudio(0);
break;
packet_queue_flush(&is->audioq);
av_free_packet(&is->audio_pkt);
- if (is->swr_ctx)
- swr_free(&is->swr_ctx);
+ swr_free(&is->swr_ctx);
av_freep(&is->audio_buf1);
is->audio_buf = NULL;
av_freep(&is->frame);
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;
}
/* if the queue are full, no need to read more */
- if ( is->audioq.size + is->videoq.size + is->subtitleq.size > MAX_QUEUE_SIZE
+ if (!infinite_buffer &&
+ (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)
- && (is->subtitleq.nb_packets > MIN_FRAMES || is->subtitle_stream < 0 || is->subtitleq.abort_request))) {
+ && (is->subtitleq.nb_packets > MIN_FRAMES || is->subtitle_stream < 0 || is->subtitleq.abort_request)))) {
/* wait 10 ms */
SDL_Delay(10);
continue;
static void toggle_full_screen(VideoState *is)
{
- av_unused int i;
- is_full_screen = !is_full_screen;
#if defined(__APPLE__) && SDL_VERSION_ATLEAST(1, 2, 14)
/* OS X needs to reallocate the SDL overlays */
- for (i = 0; i < VIDEO_PICTURE_QUEUE_SIZE; i++) {
+ int i;
+ for (i = 0; i < VIDEO_PICTURE_QUEUE_SIZE; i++)
is->pictq[i].reallocate = 1;
- }
#endif
+ is_full_screen = !is_full_screen;
video_open(is, 1);
}
{ "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" },
{
int flags;
VideoState *is;
+ char dummy_videodriver[] = "SDL_VIDEODRIVER=dummy";
av_log_set_flags(AV_LOG_SKIP_REPEATED);
parse_loglevel(argc, argv, options);
flags = SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER;
if (audio_disable)
flags &= ~SDL_INIT_AUDIO;
+ if (display_disable)
+ SDL_putenv(dummy_videodriver); /* For the event queue, we always need a video driver. */
#if !defined(__MINGW32__) && !defined(__APPLE__)
flags |= SDL_INIT_EVENTTHREAD; /* Not supported on Windows or Mac OS X */
#endif