#include "libavformat/avformat.h"
#include "libavdevice/avdevice.h"
#include "libswscale/swscale.h"
-#include "libavcodec/audioconvert.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"
#endif
#include "cmdutils.h"
int64_t seek_rel;
int read_pause_return;
AVFormatContext *ic;
- int dtg_active_format;
int audio_stream;
int audio_buf_index; /* in bytes */
AVPacket audio_pkt_temp;
AVPacket audio_pkt;
- enum AVSampleFormat audio_src_fmt;
- AVAudioConvert *reformat_ctx;
+ enum AVSampleFormat sdl_sample_fmt;
+ uint64_t sdl_channel_layout;
+ int sdl_channels;
+ enum AVSampleFormat resample_sample_fmt;
+ uint64_t resample_channel_layout;
+ AVAudioResampleContext *avr;
AVFrame *frame;
int show_audio; /* if true, display audio samples */
static int debug = 0;
static int debug_mv = 0;
static int step = 0;
-static int thread_count = 1;
static int workaround_bugs = 1;
static int fast = 0;
static int genpts = 0;
-static int lowres = 0;
static int idct = FF_IDCT_AUTO;
static enum AVDiscard skip_frame = AVDISCARD_DEFAULT;
static enum AVDiscard skip_idct = AVDISCARD_DEFAULT;
static enum AVDiscard skip_loop_filter = AVDISCARD_DEFAULT;
-static int error_recognition = FF_ER_CAREFUL;
static int error_concealment = 3;
static int decoder_reorder_pts = -1;
static int autoexit;
nb_freq = 1 << (rdft_bits - 1);
/* compute display index : center on currently output samples */
- channels = s->audio_st->codec->channels;
+ channels = s->sdl_channels;
nb_display_channels = channels;
if (!s->paused) {
int data_used = s->show_audio == 1 ? s->width : (2 * nb_freq);
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 *
- 2 * is->audio_st->codec->channels;
+ bytes_per_sec = is->audio_st->codec->sample_rate * is->sdl_channels *
+ av_get_bytes_per_sample(is->sdl_sample_fmt);
}
if (bytes_per_sec)
pts -= (double)hw_buf_size / bytes_per_sec;
/* SDL allocates a buffer smaller than requested if the video
* overlay hardware is unable to support the requested size. */
fprintf(stderr, "Error: the video system does not support an image\n"
- "size of %dx%d pixels. Try using -lowres or -vf \"scale=w:h\"\n"
+ "size of %dx%d pixels. Try using -vf \"scale=w:h\"\n"
"to reduce the image size.\n", vp->width, vp->height );
do_exit();
}
/* if the frame is not skipped, then display it */
if (vp->bmp) {
- AVPicture pict;
+ AVPicture pict = { { 0 } };
#if CONFIG_AVFILTER
if (vp->picref)
avfilter_unref_buffer(vp->picref);
/* get a pointer on the bitmap */
SDL_LockYUVOverlay (vp->bmp);
- memset(&pict, 0, sizeof(AVPicture));
pict.data[0] = vp->bmp->pixels[0];
pict.data[1] = vp->bmp->pixels[2];
pict.data[2] = vp->bmp->pixels[1];
AVFilterContext *ctx = codec->opaque;
AVFilterBufferRef *ref;
int perms = AV_PERM_WRITE;
- int i, w, h, stride[4];
+ int i, w, h, stride[AV_NUM_DATA_POINTERS];
unsigned edge;
int pixel_size;
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;
{
char sws_flags_str[128];
int ret;
- FFSinkContext ffsink_ctx = { .pix_fmt = PIX_FMT_YUV420P };
- AVFilterContext *filt_src = NULL, *filt_out = NULL;
+ AVFilterContext *filt_src = NULL, *filt_out = NULL, *filt_format;
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)
return ret;
- if ((ret = avfilter_graph_create_filter(&filt_out, &ffsink, "out",
- NULL, &ffsink_ctx, graph)) < 0)
+ if ((ret = avfilter_graph_create_filter(&filt_out,
+ avfilter_get_by_name("buffersink"),
+ "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;
+
+
if (vfilters) {
- AVFilterInOut *outputs = av_malloc(sizeof(AVFilterInOut));
- AVFilterInOut *inputs = av_malloc(sizeof(AVFilterInOut));
+ AVFilterInOut *outputs = avfilter_inout_alloc();
+ AVFilterInOut *inputs = avfilter_inout_alloc();
outputs->name = av_strdup("in");
outputs->filter_ctx = filt_src;
outputs->next = NULL;
inputs->name = av_strdup("out");
- inputs->filter_ctx = filt_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;
- av_freep(&vfilters);
} else {
- if ((ret = avfilter_link(filt_src, 0, filt_out, 0)) < 0)
+ if ((ret = avfilter_link(filt_src, 0, filt_format, 0)) < 0)
return ret;
}
last_w = is->video_st->codec->width;
last_h = is->video_st->codec->height;
}
- ret = get_filtered_video_frame(filt_out, frame, &picref, &tb);
+ ret = av_buffersink_read(filt_out, &picref);
if (picref) {
+ avfilter_copy_buf_props(frame, picref);
+
pts_int = picref->pts;
+ tb = filt_out->inputs[0]->time_base;
pos = picref->pos;
frame->opaque = picref;
+
+ ret = 1;
}
- if (av_cmp_q(tb, is->video_st->time_base)) {
+ 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(): "
}
the_end:
#if CONFIG_AVFILTER
+ av_freep(&vfilters);
avfilter_graph_free(&graph);
#endif
av_free(frame);
int n, samples_size;
double ref_clock;
- n = 2 * is->audio_st->codec->channels;
+ n = is->sdl_channels * av_get_bytes_per_sample(is->sdl_sample_fmt);
samples_size = samples_size1;
/* if not master, then we try to remove or add samples to correct the clock */
for (;;) {
/* NOTE: the audio packet can contain several frames */
while (pkt_temp->size > 0 || (!pkt_temp->data && new_packet)) {
+ int resample_changed, audio_resample;
+
if (!is->frame) {
if (!(is->frame = avcodec_alloc_frame()))
return AVERROR(ENOMEM);
is->frame->nb_samples,
dec->sample_fmt, 1);
- if (dec->sample_fmt != is->audio_src_fmt) {
- if (is->reformat_ctx)
- av_audio_convert_free(is->reformat_ctx);
- is->reformat_ctx= av_audio_convert_alloc(AV_SAMPLE_FMT_S16, 1,
- dec->sample_fmt, 1, NULL, 0);
- if (!is->reformat_ctx) {
- fprintf(stderr, "Cannot convert %s sample format to %s sample format\n",
- av_get_sample_fmt_name(dec->sample_fmt),
- av_get_sample_fmt_name(AV_SAMPLE_FMT_S16));
+ audio_resample = dec->sample_fmt != is->sdl_sample_fmt ||
+ dec->channel_layout != is->sdl_channel_layout;
+
+ resample_changed = dec->sample_fmt != is->resample_sample_fmt ||
+ dec->channel_layout != is->resample_channel_layout;
+
+ if ((!is->avr && audio_resample) || resample_changed) {
+ int ret;
+ if (is->avr)
+ avresample_close(is->avr);
+ else if (audio_resample) {
+ is->avr = avresample_alloc_context();
+ if (!is->avr) {
+ fprintf(stderr, "error allocating AVAudioResampleContext\n");
break;
+ }
+ }
+ 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);
+ if (av_get_bytes_per_sample(dec->sample_fmt) <= 2)
+ av_opt_set_int(is->avr, "internal_sample_fmt", AV_SAMPLE_FMT_S16P, 0);
+
+ if ((ret = avresample_open(is->avr)) < 0) {
+ fprintf(stderr, "error initializing libavresample\n");
+ break;
+ }
}
- is->audio_src_fmt= dec->sample_fmt;
+ is->resample_sample_fmt = dec->sample_fmt;
+ is->resample_channel_layout = dec->channel_layout;
}
- if (is->reformat_ctx) {
- const void *ibuf[6] = { is->frame->data[0] };
- void *obuf[6];
- int istride[6] = { av_get_bytes_per_sample(dec->sample_fmt) };
- int ostride[6] = { 2 };
- int len= data_size/istride[0];
- obuf[0] = av_realloc(is->audio_buf1, FFALIGN(len * ostride[0], 32));
- if (!obuf[0]) {
+ if (audio_resample) {
+ void *tmp_out;
+ int out_samples, out_size, out_linesize;
+ int osize = av_get_bytes_per_sample(is->sdl_sample_fmt);
+ int nb_samples = is->frame->nb_samples;
+
+ out_size = av_samples_get_buffer_size(&out_linesize,
+ is->sdl_channels,
+ nb_samples,
+ is->sdl_sample_fmt, 0);
+ tmp_out = av_realloc(is->audio_buf1, out_size);
+ if (!tmp_out)
return AVERROR(ENOMEM);
- }
- is->audio_buf1 = obuf[0];
- if (av_audio_convert(is->reformat_ctx, obuf, ostride, ibuf, istride, len) < 0) {
- printf("av_audio_convert() failed\n");
+ is->audio_buf1 = tmp_out;
+
+ out_samples = avresample_convert(is->avr,
+ (void **)&is->audio_buf1,
+ out_linesize, nb_samples,
+ (void **)is->frame->data,
+ is->frame->linesize[0],
+ is->frame->nb_samples);
+ if (out_samples < 0) {
+ fprintf(stderr, "avresample_convert() failed\n");
break;
}
is->audio_buf = is->audio_buf1;
- /* FIXME: existing code assume that data_size equals framesize*channels*2
- remove this legacy cruft */
- data_size = len * 2;
+ data_size = out_samples * osize * is->sdl_channels;
} else {
is->audio_buf = is->frame->data[0];
}
/* if no pts, then compute it */
pts = is->audio_clock;
*pts_ptr = pts;
- n = 2 * dec->channels;
+ n = is->sdl_channels * av_get_bytes_per_sample(is->sdl_sample_fmt);
is->audio_clock += (double)data_size /
(double)(n * dec->sample_rate);
#ifdef DEBUG
if ((new_packet = packet_queue_get(&is->audioq, pkt, 1)) < 0)
return -1;
- if (pkt->data == flush_pkt.data)
+ if (pkt->data == flush_pkt.data) {
avcodec_flush_buffers(dec);
+ flush_complete = 0;
+ }
*pkt_temp = *pkt;
avctx->debug_mv = debug_mv;
avctx->debug = debug;
avctx->workaround_bugs = workaround_bugs;
- avctx->lowres = lowres;
avctx->idct_algo = idct;
avctx->skip_frame = skip_frame;
avctx->skip_idct = skip_idct;
avctx->skip_loop_filter = skip_loop_filter;
- avctx->error_recognition = error_recognition;
avctx->error_concealment = error_concealment;
- avctx->thread_count = thread_count;
- if (lowres) avctx->flags |= CODEC_FLAG_EMU_EDGE;
if (fast) avctx->flags2 |= CODEC_FLAG2_FAST;
+ if (!av_dict_get(opts, "threads", NULL, 0))
+ av_dict_set(&opts, "threads", "auto", 0);
if (!codec ||
avcodec_open2(avctx, codec, &opts) < 0)
return -1;
if (avctx->codec_type == AVMEDIA_TYPE_AUDIO) {
wanted_spec.freq = avctx->sample_rate;
wanted_spec.format = AUDIO_S16SYS;
- wanted_spec.channels = avctx->channels;
+
+ 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;
+ }
+ if (avctx->channels == 1)
+ is->sdl_channel_layout = AV_CH_LAYOUT_MONO;
+ else
+ is->sdl_channel_layout = AV_CH_LAYOUT_STEREO;
+ is->sdl_channels = av_get_channel_layout_nb_channels(is->sdl_channel_layout);
+
+ wanted_spec.channels = is->sdl_channels;
wanted_spec.silence = 0;
wanted_spec.samples = SDL_AUDIO_BUFFER_SIZE;
wanted_spec.callback = sdl_audio_callback;
return -1;
}
is->audio_hw_buf_size = spec.size;
- is->audio_src_fmt = AV_SAMPLE_FMT_S16;
+ is->sdl_sample_fmt = AV_SAMPLE_FMT_S16;
+ is->resample_sample_fmt = is->sdl_sample_fmt;
+ is->resample_channel_layout = is->sdl_channel_layout;
}
ic->streams[stream_index]->discard = AVDISCARD_DEFAULT;
packet_queue_end(&is->audioq);
av_free_packet(&is->audio_pkt);
- if (is->reformat_ctx)
- av_audio_convert_free(is->reformat_ctx);
- is->reformat_ctx = NULL;
+ if (is->avr)
+ avresample_free(&is->avr);
av_freep(&is->audio_buf1);
is->audio_buf = NULL;
av_freep(&is->frame);
{
is_full_screen = !is_full_screen;
#if defined(__APPLE__) && SDL_VERSION_ATLEAST(1, 2, 14)
- /* OSX needs to empty the picture_queue */
+ /* OS X needs to empty the picture_queue */
for (int i = 0; i < VIDEO_PICTURE_QUEUE_SIZE; i++) {
cur_stream->pictq[i].reallocate = 1;
}
return 0;
}
-static int opt_thread_count(const char *opt, const char *arg)
-{
- thread_count = parse_number_or_die(opt, arg, OPT_INT64, 0, INT_MAX);
-#if !HAVE_THREADS
- fprintf(stderr, "Warning: not compiled with thread support, using thread emulation\n");
-#endif
- return 0;
-}
-
static const OptionDef options[] = {
#include "cmdutils_common_opts.h"
{ "x", HAS_ARG, { (void*)opt_width }, "force displayed width", "width" },
{ "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", ""},
- { "lowres", OPT_INT | HAS_ARG | OPT_EXPERT, { (void*)&lowres }, "", "" },
{ "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" },
- { "er", OPT_INT | HAS_ARG | OPT_EXPERT, { (void*)&error_recognition }, "set error detection threshold (0-4)", "threshold" },
{ "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" },
- { "threads", HAS_ARG | OPT_EXPERT, { (void*)opt_thread_count }, "thread count", "count" },
{ "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", "" },