libav: Integrate FFmpeg's DSD support with GstDsd caps

Code is partially based on the DSD of Robert Tiemann <rtie@gmx.de>:
https://gitlab.freedesktop.org/rtiemann/gstreamer/-/tree/dsd

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3901>
This commit is contained in:
Carlos Rafael Giani 2023-02-05 11:15:44 +01:00 committed by GStreamer Marge Bot
parent 8febc4102a
commit 34238e251d
3 changed files with 95 additions and 25 deletions

View file

@ -6659,7 +6659,7 @@
"long-name": "libav DSD (Direct Stream Digital), least significant bit first decoder",
"pad-templates": {
"sink": {
"caps": "audio/x-dsd:\n lsbf: true\n planar: false\n",
"caps": "audio/x-dsd:\n format: DSDU8\n reversed-bytes: true\n layout: interleaved\n",
"direction": "sink",
"presence": "always"
},
@ -6687,7 +6687,7 @@
"long-name": "libav DSD (Direct Stream Digital), least significant bit first, planar decoder",
"pad-templates": {
"sink": {
"caps": "audio/x-dsd:\n lsbf: true\n planar: true\n",
"caps": "audio/x-dsd:\n format: DSDU8\n reversed-bytes: true\n layout: non-interleaved\n",
"direction": "sink",
"presence": "always"
},
@ -6715,7 +6715,7 @@
"long-name": "libav DSD (Direct Stream Digital), most significant bit first decoder",
"pad-templates": {
"sink": {
"caps": "audio/x-dsd:\n lsbf: false\n planar: false\n",
"caps": "audio/x-dsd:\n format: DSDU8\n reversed-bytes: false\n layout: interleaved\n",
"direction": "sink",
"presence": "always"
},
@ -6743,7 +6743,7 @@
"long-name": "libav DSD (Direct Stream Digital), most significant bit first, planar decoder",
"pad-templates": {
"sink": {
"caps": "audio/x-dsd:\n lsbf: false\n planar: true\n",
"caps": "audio/x-dsd:\n format: DSDU8\n reversed-bytes: false\n layout: non-interleaved\n",
"direction": "sink",
"presence": "always"
},

View file

@ -34,6 +34,7 @@
#include <gst/video/video.h>
#include <gst/audio/audio.h>
#include <gst/audio/gstdsd.h>
#include <gst/pbutils/codec-utils.h>
/* IMPORTANT: Keep this sorted by the ffmpeg channel masks */
@ -640,6 +641,36 @@ gst_ff_aud_caps_new (AVCodecContext * context, AVCodec * codec,
rates = l_rates;
break;
}
case AV_CODEC_ID_DSD_LSBF:
case AV_CODEC_ID_DSD_MSBF:
case AV_CODEC_ID_DSD_LSBF_PLANAR:
case AV_CODEC_ID_DSD_MSBF_PLANAR:
{
const static gint l_rates[] = {
GST_DSD_MAKE_DSD_RATE_44x (64),
GST_DSD_MAKE_DSD_RATE_48x (64),
GST_DSD_MAKE_DSD_RATE_44x (128),
GST_DSD_MAKE_DSD_RATE_48x (128),
GST_DSD_MAKE_DSD_RATE_44x (256),
GST_DSD_MAKE_DSD_RATE_48x (256),
GST_DSD_MAKE_DSD_RATE_44x (512),
GST_DSD_MAKE_DSD_RATE_48x (512),
GST_DSD_MAKE_DSD_RATE_44x (1024),
GST_DSD_MAKE_DSD_RATE_48x (1024),
GST_DSD_MAKE_DSD_RATE_44x (2048),
GST_DSD_MAKE_DSD_RATE_48x (2048),
};
/* There is no clearly defined maximum number of channels in DSD.
* The DSF spec mentions a maximum of 6 channels, while the DSDIFF
* spec mentions up to 65535 channels. DSDIFF stores DSD in an
* interleaved, DSF in a planar fashion. But there is no reason
* why some other format couldn't have more than 6 interleaved
* channels for example. */
maxchannels = 65535;
n_rates = G_N_ELEMENTS (l_rates);
rates = l_rates;
break;
}
default:
break;
}
@ -2318,33 +2349,45 @@ gst_ffmpeg_codecid_to_caps (enum AVCodecID codec_id,
NULL);
break;
case AV_CODEC_ID_DSD_LSBF:
caps =
gst_ff_aud_caps_new (context, NULL, codec_id, encode, "audio/x-dsd",
NULL);
gst_caps_set_simple (caps, "lsbf", G_TYPE_BOOLEAN,
TRUE, "planar", G_TYPE_BOOLEAN, FALSE, NULL);
break;
case AV_CODEC_ID_DSD_MSBF:
caps =
gst_ff_aud_caps_new (context, NULL, codec_id, encode, "audio/x-dsd",
NULL);
gst_caps_set_simple (caps, "lsbf", G_TYPE_BOOLEAN,
FALSE, "planar", G_TYPE_BOOLEAN, FALSE, NULL);
break;
case AV_CODEC_ID_DSD_LSBF_PLANAR:
caps =
gst_ff_aud_caps_new (context, NULL, codec_id, encode, "audio/x-dsd",
NULL);
gst_caps_set_simple (caps, "lsbf", G_TYPE_BOOLEAN,
TRUE, "planar", G_TYPE_BOOLEAN, TRUE, NULL);
break;
case AV_CODEC_ID_DSD_MSBF_PLANAR:
{
gboolean reversed_bytes;
gboolean interleaved;
switch (codec_id) {
case AV_CODEC_ID_DSD_LSBF:
reversed_bytes = TRUE;
interleaved = TRUE;
break;
case AV_CODEC_ID_DSD_MSBF:
reversed_bytes = FALSE;
interleaved = TRUE;
break;
case AV_CODEC_ID_DSD_LSBF_PLANAR:
reversed_bytes = TRUE;
interleaved = FALSE;
break;
case AV_CODEC_ID_DSD_MSBF_PLANAR:
reversed_bytes = FALSE;
interleaved = FALSE;
break;
default:
reversed_bytes = FALSE;
interleaved = FALSE;
break;
}
caps =
gst_ff_aud_caps_new (context, NULL, codec_id, encode, "audio/x-dsd",
NULL);
gst_caps_set_simple (caps, "lsbf", G_TYPE_BOOLEAN,
FALSE, "planar", G_TYPE_BOOLEAN, TRUE, NULL);
"format", G_TYPE_STRING, "DSDU8",
"reversed-bytes", G_TYPE_BOOLEAN, reversed_bytes,
"layout", G_TYPE_STRING,
(interleaved) ? "interleaved" : "non-interleaved", NULL);
break;
}
case AV_CODEC_ID_APTX:
caps =
gst_ff_aud_caps_new (context, NULL, codec_id, encode, "audio/aptx",

View file

@ -30,6 +30,7 @@
/* #include <ffmpeg/avi.h> */
#include <gst/gst.h>
#include <gst/base/gstflowcombiner.h>
#include <gst/audio/gstdsd.h>
#include "gstav.h"
#include "gstavcodecmap.h"
@ -1576,6 +1577,32 @@ gst_ffmpegdemux_loop (GstFFMpegDemux * demux)
stream->discont = FALSE;
}
/* If we are demuxing planar DSD data, add the necessary
* meta to inform downstream about the planar layout. */
switch (avstream->codecpar->codec_id) {
case AV_CODEC_ID_DSD_LSBF_PLANAR:
case AV_CODEC_ID_DSD_MSBF_PLANAR:
{
int channel_idx;
int num_channels = avstream->codecpar->channels;
int num_bytes_per_channel = pkt.size / num_channels;
GstDsdPlaneOffsetMeta *plane_ofs_meta;
plane_ofs_meta = gst_buffer_add_dsd_plane_offset_meta (outbuf,
avstream->codecpar->channels, num_bytes_per_channel, NULL);
for (channel_idx = 0; channel_idx < num_channels; ++channel_idx) {
plane_ofs_meta->offsets[channel_idx] =
num_bytes_per_channel * channel_idx;
}
break;
}
default:
break;
}
GST_DEBUG_OBJECT (demux,
"Sending out buffer time:%" GST_TIME_FORMAT " size:%" G_GSIZE_FORMAT,
GST_TIME_ARGS (timestamp), gst_buffer_get_size (outbuf));