X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;ds=sidebyside;f=avplay.c;h=d291ba384a1e9628301766b688a27cc74f65cf6b;hb=9ccbdc0acafcfd1947e019c24817f2526581da49;hp=0d72f466f991c2607c02818c56a9ad56c2ec4831;hpb=2bcbd98459915baefc15043d02f4a942ebcd33da;p=ffmpeg diff --git a/avplay.c b/avplay.c index 0d72f466f99..d291ba384a1 100644 --- a/avplay.c +++ b/avplay.c @@ -34,13 +34,14 @@ #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" @@ -159,8 +160,12 @@ typedef struct VideoState { 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 */ @@ -743,7 +748,7 @@ static void video_audio_display(VideoState *s) 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); @@ -957,8 +962,8 @@ 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 * - 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; @@ -1704,21 +1709,28 @@ static AVFilter input_filter = 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]; int ret; - SinkContext sink_ctx = { .pix_fmts = pix_fmts }; - 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, &sink, "out", - NULL, &sink_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 = avfilter_inout_alloc(); AVFilterInOut *inputs = avfilter_inout_alloc(); @@ -1729,14 +1741,14 @@ static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const c 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; } 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; } @@ -1792,11 +1804,16 @@ static int video_thread(void *arg) 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 (ret >= 0 && av_cmp_q(tb, is->video_st->time_base)) { @@ -1937,7 +1954,7 @@ static int synchronize_audio(VideoState *is, short *samples, 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 */ @@ -2018,6 +2035,8 @@ static int audio_decode_frame(VideoState *is, double *pts_ptr) 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); @@ -2047,39 +2066,69 @@ static int audio_decode_frame(VideoState *is, double *pts_ptr) 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; + } } - is->audio_src_fmt= dec->sample_fmt; + 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->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]; } @@ -2087,7 +2136,7 @@ static int audio_decode_frame(VideoState *is, double *pts_ptr) /* 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 @@ -2206,7 +2255,20 @@ static int stream_component_open(VideoState *is, int stream_index) 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; @@ -2216,7 +2278,9 @@ static int stream_component_open(VideoState *is, int stream_index) 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; @@ -2275,9 +2339,8 @@ static void stream_component_close(VideoState *is, int stream_index) 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);