Commit 4893c204 authored by Stefano Sabatini's avatar Stefano Sabatini Committed by Stefano Sabatini

lavdev/lavfi: add audio support

parent 3ee0bedc
...@@ -56,6 +56,7 @@ easier to use. The changes are: ...@@ -56,6 +56,7 @@ easier to use. The changes are:
- Prores decoder - Prores decoder
- BIN/XBIN/ADF/IDF text file decoder - BIN/XBIN/ADF/IDF text file decoder
- aconvert audio filter added - aconvert audio filter added
- audio support to lavfi input device added
version 0.8: version 0.8:
......
...@@ -266,6 +266,21 @@ Create three different video test filtered sources and play them: ...@@ -266,6 +266,21 @@ Create three different video test filtered sources and play them:
@example @example
ffplay -f lavfi -graph "testsrc [out0]; testsrc,hflip [out1]; testsrc,negate [out2]" test3 ffplay -f lavfi -graph "testsrc [out0]; testsrc,hflip [out1]; testsrc,negate [out2]" test3
@end example @end example
@item
Read an audio stream from a file using the amovie source and play it
back with @file{ffplay}:
@example
ffplay -f lavfi "amovie=test.wav"
@end example
@item
Read an audio stream and a video stream and play it back with
@file{ffplay}:
@example
ffplay -f lavfi "movie=test.avi[out0];amovie=test.wav[out1]"
@end example
@end itemize @end itemize
@section libdc1394 @section libdc1394
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
#define LIBAVDEVICE_VERSION_MAJOR 53 #define LIBAVDEVICE_VERSION_MAJOR 53
#define LIBAVDEVICE_VERSION_MINOR 3 #define LIBAVDEVICE_VERSION_MINOR 3
#define LIBAVDEVICE_VERSION_MICRO 2 #define LIBAVDEVICE_VERSION_MICRO 3
#define LIBAVDEVICE_VERSION_INT AV_VERSION_INT(LIBAVDEVICE_VERSION_MAJOR, \ #define LIBAVDEVICE_VERSION_INT AV_VERSION_INT(LIBAVDEVICE_VERSION_MAJOR, \
LIBAVDEVICE_VERSION_MINOR, \ LIBAVDEVICE_VERSION_MINOR, \
......
...@@ -80,19 +80,17 @@ av_cold static int lavfi_read_header(AVFormatContext *avctx, ...@@ -80,19 +80,17 @@ av_cold static int lavfi_read_header(AVFormatContext *avctx,
{ {
LavfiContext *lavfi = avctx->priv_data; LavfiContext *lavfi = avctx->priv_data;
AVFilterInOut *input_links = NULL, *output_links = NULL, *inout; AVFilterInOut *input_links = NULL, *output_links = NULL, *inout;
AVFilter *buffersink; AVFilter *buffersink, *abuffersink;
int *pix_fmts = create_all_formats(PIX_FMT_NB); int *pix_fmts = create_all_formats(PIX_FMT_NB);
enum AVMediaType type;
int ret = 0, i, n; int ret = 0, i, n;
#define FAIL(ERR) { ret = ERR; goto end; } #define FAIL(ERR) { ret = ERR; goto end; }
avfilter_register_all(); avfilter_register_all();
if (!(buffersink = avfilter_get_by_name("buffersink"))) { buffersink = avfilter_get_by_name("buffersink");
av_log(avctx, AV_LOG_ERROR, abuffersink = avfilter_get_by_name("abuffersink");
"Missing required buffersink filter, aborting.\n");
FAIL(AVERROR_FILTER_NOT_FOUND);
}
if (!lavfi->graph_str) if (!lavfi->graph_str)
lavfi->graph_str = av_strdup(avctx->filename); lavfi->graph_str = av_strdup(avctx->filename);
...@@ -143,9 +141,10 @@ av_cold static int lavfi_read_header(AVFormatContext *avctx, ...@@ -143,9 +141,10 @@ av_cold static int lavfi_read_header(AVFormatContext *avctx,
} }
/* is a video output? */ /* is a video output? */
if (inout->filter_ctx->output_pads[inout->pad_idx].type != AVMEDIA_TYPE_VIDEO) { type = inout->filter_ctx->output_pads[inout->pad_idx].type;
if (type != AVMEDIA_TYPE_VIDEO && type != AVMEDIA_TYPE_AUDIO) {
av_log(avctx, AV_LOG_ERROR, av_log(avctx, AV_LOG_ERROR,
"Output '%s' is not a video output, not yet supported", inout->name); "Output '%s' is not a video or audio output, not yet supported\n", inout->name);
FAIL(AVERROR(EINVAL)); FAIL(AVERROR(EINVAL));
} }
...@@ -173,7 +172,19 @@ av_cold static int lavfi_read_header(AVFormatContext *avctx, ...@@ -173,7 +172,19 @@ av_cold static int lavfi_read_header(AVFormatContext *avctx,
for (i = 0, inout = output_links; inout; i++, inout = inout->next) { for (i = 0, inout = output_links; inout; i++, inout = inout->next) {
AVFilterContext *sink; AVFilterContext *sink;
type = inout->filter_ctx->output_pads[inout->pad_idx].type;
if (type == AVMEDIA_TYPE_VIDEO && ! buffersink ||
type == AVMEDIA_TYPE_AUDIO && ! abuffersink) {
av_log(avctx, AV_LOG_ERROR, "Missing required buffersink filter, aborting.\n");
FAIL(AVERROR_FILTER_NOT_FOUND);
}
if (type == AVMEDIA_TYPE_VIDEO) {
AVBufferSinkParams *buffersink_params = av_buffersink_params_alloc(); AVBufferSinkParams *buffersink_params = av_buffersink_params_alloc();
buffersink_params->pixel_fmts = pix_fmts;
#if FF_API_OLD_VSINK_API #if FF_API_OLD_VSINK_API
ret = avfilter_graph_create_filter(&sink, buffersink, ret = avfilter_graph_create_filter(&sink, buffersink,
inout->name, NULL, inout->name, NULL,
...@@ -185,8 +196,25 @@ av_cold static int lavfi_read_header(AVFormatContext *avctx, ...@@ -185,8 +196,25 @@ av_cold static int lavfi_read_header(AVFormatContext *avctx,
buffersink_params, lavfi->graph); buffersink_params, lavfi->graph);
#endif #endif
av_freep(&buffersink_params); av_freep(&buffersink_params);
if (ret < 0) if (ret < 0)
goto end; goto end;
} else if (type == AVMEDIA_TYPE_AUDIO) {
enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_S16, -1 };
const int packing_fmts[] = { AVFILTER_PACKED, -1 };
const int64_t *chlayouts = avfilter_all_channel_layouts;
AVABufferSinkParams *abuffersink_params = av_abuffersink_params_alloc();
abuffersink_params->sample_fmts = sample_fmts;
abuffersink_params->packing_fmts = packing_fmts;
abuffersink_params->channel_layouts = chlayouts;
ret = avfilter_graph_create_filter(&sink, abuffersink,
inout->name, NULL,
abuffersink_params, lavfi->graph);
av_free(abuffersink_params);
if (ret < 0)
goto end;
}
lavfi->sinks[i] = sink; lavfi->sinks[i] = sink;
if ((ret = avfilter_link(inout->filter_ctx, inout->pad_idx, sink, 0)) < 0) if ((ret = avfilter_link(inout->filter_ctx, inout->pad_idx, sink, 0)) < 0)
...@@ -211,6 +239,13 @@ av_cold static int lavfi_read_header(AVFormatContext *avctx, ...@@ -211,6 +239,13 @@ av_cold static int lavfi_read_header(AVFormatContext *avctx,
st->codec->height = link->h; st->codec->height = link->h;
st ->sample_aspect_ratio = st ->sample_aspect_ratio =
st->codec->sample_aspect_ratio = link->sample_aspect_ratio; st->codec->sample_aspect_ratio = link->sample_aspect_ratio;
} else if (link->type == AVMEDIA_TYPE_AUDIO) {
st->codec->codec_id = CODEC_ID_PCM_S16LE;
st->codec->channels = av_get_channel_layout_nb_channels(link->channel_layout);
st->codec->sample_fmt = link->format;
st->codec->sample_rate = link->sample_rate;
st->codec->time_base = link->time_base;
st->codec->channel_layout = link->channel_layout;
} }
} }
...@@ -226,8 +261,8 @@ static int lavfi_read_packet(AVFormatContext *avctx, AVPacket *pkt) ...@@ -226,8 +261,8 @@ static int lavfi_read_packet(AVFormatContext *avctx, AVPacket *pkt)
{ {
LavfiContext *lavfi = avctx->priv_data; LavfiContext *lavfi = avctx->priv_data;
double min_pts = DBL_MAX; double min_pts = DBL_MAX;
int min_pts_sink_idx = 0; int stream_idx, min_pts_sink_idx = 0;
AVFilterBufferRef *picref; AVFilterBufferRef *ref;
AVPicture pict; AVPicture pict;
int ret, i, size; int ret, i, size;
...@@ -237,10 +272,10 @@ static int lavfi_read_packet(AVFormatContext *avctx, AVPacket *pkt) ...@@ -237,10 +272,10 @@ static int lavfi_read_packet(AVFormatContext *avctx, AVPacket *pkt)
AVRational tb = lavfi->sinks[i]->inputs[0]->time_base; AVRational tb = lavfi->sinks[i]->inputs[0]->time_base;
double d; double d;
int ret = av_buffersink_get_buffer_ref(lavfi->sinks[i], int ret = av_buffersink_get_buffer_ref(lavfi->sinks[i],
&picref, AV_BUFFERSINK_FLAG_PEEK); &ref, AV_BUFFERSINK_FLAG_PEEK);
if (ret < 0) if (ret < 0)
return ret; return ret;
d = av_rescale_q(picref->pts, tb, AV_TIME_BASE_Q); d = av_rescale_q(ref->pts, tb, AV_TIME_BASE_Q);
av_dlog(avctx, "sink_idx:%d time:%f\n", i, d); av_dlog(avctx, "sink_idx:%d time:%f\n", i, d);
if (d < min_pts) { if (d < min_pts) {
...@@ -250,22 +285,31 @@ static int lavfi_read_packet(AVFormatContext *avctx, AVPacket *pkt) ...@@ -250,22 +285,31 @@ static int lavfi_read_packet(AVFormatContext *avctx, AVPacket *pkt)
} }
av_dlog(avctx, "min_pts_sink_idx:%i\n", min_pts_sink_idx); av_dlog(avctx, "min_pts_sink_idx:%i\n", min_pts_sink_idx);
av_buffersink_get_buffer_ref(lavfi->sinks[min_pts_sink_idx], &picref, 0); av_buffersink_get_buffer_ref(lavfi->sinks[min_pts_sink_idx], &ref, 0);
stream_idx = lavfi->sink_stream_map[min_pts_sink_idx];
size = avpicture_get_size(picref->format, picref->video->w, picref->video->h); if (ref->video) {
size = avpicture_get_size(ref->format, ref->video->w, ref->video->h);
if ((ret = av_new_packet(pkt, size)) < 0) if ((ret = av_new_packet(pkt, size)) < 0)
return ret; return ret;
memcpy(pict.data, picref->data, 4*sizeof(picref->data[0])); memcpy(pict.data, ref->data, 4*sizeof(ref->data[0]));
memcpy(pict.linesize, picref->linesize, 4*sizeof(picref->linesize[0])); memcpy(pict.linesize, ref->linesize, 4*sizeof(ref->linesize[0]));
avpicture_layout(&pict, ref->format, ref->video->w,
ref->video->h, pkt->data, size);
} else if (ref->audio) {
size = ref->linesize[0];
if ((ret = av_new_packet(pkt, size)) < 0)
return ret;
memcpy(pkt->data, ref->data[0], size);
}
avpicture_layout(&pict, picref->format, picref->video->w, pkt->stream_index = stream_idx;
picref->video->h, pkt->data, size); pkt->pts = ref->pts;
pkt->stream_index = lavfi->sink_stream_map[min_pts_sink_idx]; pkt->pos = ref->pos;
pkt->pts = picref->pts;
pkt->pos = picref->pos;
pkt->size = size; pkt->size = size;
avfilter_unref_buffer(picref); avfilter_unref_buffer(ref);
return size; return size;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment