FFmpeg
libmpeghdec.c
Go to the documentation of this file.
1 /*
2  * MPEG-H 3D Audio Decoder Wrapper
3  * Copyright (C) 2025 Fraunhofer Institute for Integrated Circuits IIS
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
22 /*
23  * Please note that this FFmpeg Software is licensed under the LGPL-2.1
24  * but is combined with software that is licensed under different terms, namely
25  * the "Software License for The Fraunhofer FDK MPEG-H Software". Fraunhofer
26  * as the initial licensor does not interpret the LGPL-2.1 as requiring
27  * distribution of the MPEG-H Software under the LGPL-2.1 if being distributed
28  * together with this FFmpeg Software. Therefore, downstream distribution of
29  * FFmpeg Software does not imply any right to redistribute the MPEG-H Software
30  * under the LGPL-2.1.
31  */
32 #include <string.h>
33 #include <mpeghdec/mpeghdecoder.h>
34 
36 #include "libavutil/frame.h"
37 #include "libavutil/mem.h"
38 
39 #include "codec_internal.h"
40 #include "decode.h"
41 
42 #define MAX_LOST_FRAMES 2
43 // max framesize * (max delay frames + 1)
44 #define PER_CHANNEL_OUTBUF_SIZE (3072 * (MAX_LOST_FRAMES + 1))
45 
46 typedef struct MPEGH3DADecContext {
47  // pointer to the decoder
48  HANDLE_MPEGH_DECODER_CONTEXT decoder;
49 
50  // Internal values
52  int decoder_buffer_size; ///< in samples
54 
56 {
57  MPEGH3DADecContext *s = avctx->priv_data;
58 
59  if (s->decoder)
60  mpeghdecoder_destroy(s->decoder);
61  s->decoder = NULL;
62  av_freep(&s->decoder_buffer);
63 
64  return 0;
65 }
66 
67 // Lookup CICP for FFmpeg channel layout, see:
68 // https://github.com/Fraunhofer-IIS/mpeghdec/wiki/MPEG-H-decoder-target-layouts
70 {
71 // different from AV_CH_LAYOUT_7POINT2POINT3
72 #define CH_LAYOUT_7POINT2POINT3 AV_CH_LAYOUT_5POINT1POINT2 | AV_CH_SIDE_SURROUND_LEFT | \
73  AV_CH_SIDE_SURROUND_RIGHT | AV_CH_TOP_BACK_CENTER | \
74  AV_CH_LOW_FREQUENCY_2
75 #define CH_LAYOUT_5POINT1POINT6 AV_CH_LAYOUT_5POINT1POINT4_BACK | \
76  AV_CH_TOP_FRONT_CENTER | AV_CH_TOP_CENTER
77 #define CH_LAYOUT_7POINT1POINT6 AV_CH_LAYOUT_7POINT1POINT4_BACK | \
78  AV_CH_TOP_FRONT_CENTER | AV_CH_TOP_CENTER
79  static const uint64_t channel_layout_masks[] = {
80  0,
91  };
92  for (size_t i = 0; i < FF_ARRAY_ELEMS(channel_layout_masks); ++i) {
93  if (channel_layout_masks[i]) {
94  AVChannelLayout ch_layout;
95  av_channel_layout_from_mask(&ch_layout, channel_layout_masks[i]);
96  if (!av_channel_layout_compare(layout, &ch_layout))
97  return i;
98  }
99  }
100 
101  return 0;
102 }
103 
105 {
106  int cicp;
107 
108  MPEGH3DADecContext *s = avctx->priv_data;
109 
110  if (avctx->ch_layout.nb_channels == 0) {
111  av_log(avctx, AV_LOG_ERROR, "Channel layout needs to be specified\n");
112  return AVERROR(EINVAL);
113  } else if ((cicp = channel_layout_to_cicp(&avctx->ch_layout)) <= 0) {
114  av_log(avctx, AV_LOG_ERROR, "Unsupported channel layout\n");
115  return AVERROR(EINVAL);
116  }
117 
118  s->decoder = NULL;
119 
120  avctx->delay = 0;
121  avctx->sample_fmt = AV_SAMPLE_FMT_S32;
122  avctx->sample_rate = 48000;
123 
124  s->decoder_buffer_size = PER_CHANNEL_OUTBUF_SIZE * avctx->ch_layout.nb_channels;
125  s->decoder_buffer = av_malloc_array(s->decoder_buffer_size, sizeof(*s->decoder_buffer));
126  if (!s->decoder_buffer)
127  return AVERROR(ENOMEM);
128 
129  // initialize the decoder
130  s->decoder = mpeghdecoder_init(cicp);
131  if (s->decoder == NULL) {
132  av_log(avctx, AV_LOG_ERROR, "MPEG-H decoder library init failed.\n");
133  return AVERROR_EXTERNAL;
134  }
135 
136  if (avctx->extradata_size) {
137  if (mpeghdecoder_setMhaConfig(s->decoder, avctx->extradata,
138  avctx->extradata_size)) {
139  av_log(avctx, AV_LOG_ERROR, "Unable to set MHA configuration\n");
140  return AVERROR_INVALIDDATA;
141  }
142  }
143 
144  return 0;
145 }
146 
148  int *got_frame_ptr, AVPacket *avpkt)
149 {
150  MPEGH3DADecContext *s = avctx->priv_data;
151  int ret;
152  MPEGH_DECODER_ERROR err;
153  MPEGH_DECODER_OUTPUT_INFO out_info;
154 
155  if (!avctx->sample_rate) {
156  av_log(avctx, AV_LOG_ERROR, "Audio sample rate is not set");
157  return AVERROR_INVALIDDATA;
158  }
159 
160  if (avpkt->data != NULL && avpkt->size > 0) {
161  if ((err = mpeghdecoder_processTimescale(s->decoder, avpkt->data,
162  avpkt->size, avpkt->pts,
163  avctx->sample_rate))) {
164  av_log(avctx, AV_LOG_ERROR, "mpeghdecoder_process() failed: %x\n",
165  err);
166  return AVERROR_INVALIDDATA;
167  }
168  } else {
169  // we are flushing
170  err = mpeghdecoder_flushAndGet(s->decoder);
171 
172  if (err != MPEGH_DEC_OK && err != MPEGH_DEC_FEED_DATA)
173  av_log(avctx, AV_LOG_WARNING,
174  "mpeghdecoder_flushAndGet() failed: %d\n", err);
175  }
176 
177  err = mpeghdecoder_getSamples(s->decoder, s->decoder_buffer,
178  s->decoder_buffer_size,
179  &out_info);
180  if (err == MPEGH_DEC_FEED_DATA) {
181  // no frames to produce at the moment
182  return avpkt->size;
183  } else if (err) {
184  av_log(avctx, AV_LOG_ERROR, "mpeghdecoder_getSamples() failed: %x\n",
185  err);
186  return AVERROR_UNKNOWN;
187  }
188 
189  frame->nb_samples = out_info.numSamplesPerChannel;
190  frame->sample_rate = avctx->sample_rate = out_info.sampleRate;
191  frame->pts = out_info.ticks;
192  frame->time_base.num = 1;
193  frame->time_base.den = out_info.sampleRate;
194 
195  if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
196  return ret;
197 
198  memcpy(frame->extended_data[0], s->decoder_buffer,
199  avctx->ch_layout.nb_channels * frame->nb_samples *
200  sizeof(*s->decoder_buffer) /* only AV_SAMPLE_FMT_S32 is supported */);
201 
202  *got_frame_ptr = 1;
203  return ret = avpkt->size;
204 }
205 
207 {
208  MPEGH_DECODER_ERROR err;
209  MPEGH3DADecContext *s = avctx->priv_data;
210 
211  err = mpeghdecoder_flush(s->decoder);
212 
213  if (err != MPEGH_DEC_OK && err != MPEGH_DEC_FEED_DATA)
214  av_log(avctx, AV_LOG_WARNING, "mpeghdecoder_flush failed: %d\n", err);
215 }
216 
218  .p.name = "libmpeghdec",
219  CODEC_LONG_NAME("libmpeghdec (MPEG-H 3D Audio)"),
220  .p.type = AVMEDIA_TYPE_AUDIO,
222  .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY |
224  .caps_internal = FF_CODEC_CAP_INIT_CLEANUP,
225  .priv_data_size = sizeof(MPEGH3DADecContext),
228  .flush = mpegh3dadec_flush,
229  .close = mpegh3dadec_close,
230  .p.wrapper_name = "libmpeghdec",
231 };
AV_CH_LAYOUT_6POINT1
#define AV_CH_LAYOUT_6POINT1
Definition: channel_layout.h:235
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:216
FF_CODEC_CAP_INIT_CLEANUP
#define FF_CODEC_CAP_INIT_CLEANUP
The codec allows calling the close function for deallocation even if the init function returned a fai...
Definition: codec_internal.h:42
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
AVCodecContext::sample_rate
int sample_rate
samples per second
Definition: avcodec.h:1024
AV_CH_LAYOUT_MONO
#define AV_CH_LAYOUT_MONO
Definition: channel_layout.h:217
channel_layout_to_cicp
static av_cold int channel_layout_to_cicp(const AVChannelLayout *layout)
Definition: libmpeghdec.c:69
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:427
AVPacket::data
uint8_t * data
Definition: packet.h:558
FFCodec
Definition: codec_internal.h:127
MPEGH3DADecContext::decoder_buffer_size
int decoder_buffer_size
in samples
Definition: libmpeghdec.c:52
AVERROR_UNKNOWN
#define AVERROR_UNKNOWN
Unknown error, typically from an external library.
Definition: error.h:73
AVChannelLayout::nb_channels
int nb_channels
Number of channels in this layout.
Definition: channel_layout.h:329
AVCodecContext::delay
int delay
Codec delay.
Definition: avcodec.h:575
mpegh3dadec_decode_frame
static int mpegh3dadec_decode_frame(AVCodecContext *avctx, AVFrame *frame, int *got_frame_ptr, AVPacket *avpkt)
Definition: libmpeghdec.c:147
AV_CODEC_ID_MPEGH_3D_AUDIO
@ AV_CODEC_ID_MPEGH_3D_AUDIO
Definition: codec_id.h:550
FFCodec::p
AVCodec p
The public AVCodec.
Definition: codec_internal.h:131
AVCodecContext::ch_layout
AVChannelLayout ch_layout
Audio channel layout.
Definition: avcodec.h:1039
AV_CH_LAYOUT_5POINT1POINT4_BACK
#define AV_CH_LAYOUT_5POINT1POINT4_BACK
Definition: channel_layout.h:247
AV_CH_LAYOUT_STEREO
#define AV_CH_LAYOUT_STEREO
Definition: channel_layout.h:218
CH_LAYOUT_5POINT1POINT6
#define CH_LAYOUT_5POINT1POINT6
AV_CH_LAYOUT_7POINT1POINT4_BACK
#define AV_CH_LAYOUT_7POINT1POINT4_BACK
Definition: channel_layout.h:249
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:210
FF_ARRAY_ELEMS
#define FF_ARRAY_ELEMS(a)
Definition: sinewin_tablegen.c:29
av_cold
#define av_cold
Definition: attributes.h:100
MPEGH3DADecContext::decoder
HANDLE_MPEGH_DECODER_CONTEXT decoder
Definition: libmpeghdec.c:48
AV_CH_LAYOUT_22POINT2
#define AV_CH_LAYOUT_22POINT2
Definition: channel_layout.h:256
AVCodecContext::extradata_size
int extradata_size
Definition: avcodec.h:515
FF_CODEC_DECODE_CB
#define FF_CODEC_DECODE_CB(func)
Definition: codec_internal.h:346
s
#define s(width, name)
Definition: cbs_vp9.c:198
AVMEDIA_TYPE_AUDIO
@ AVMEDIA_TYPE_AUDIO
Definition: avutil.h:201
av_channel_layout_from_mask
int av_channel_layout_from_mask(AVChannelLayout *channel_layout, uint64_t mask)
Initialize a native channel layout from a bitmask indicating which channels are present.
Definition: channel_layout.c:252
decode.h
CODEC_LONG_NAME
#define CODEC_LONG_NAME(str)
Definition: codec_internal.h:331
AV_CH_LAYOUT_2_1
#define AV_CH_LAYOUT_2_1
Definition: channel_layout.h:220
mpegh3dadec_close
static av_cold int mpegh3dadec_close(AVCodecContext *avctx)
Definition: libmpeghdec.c:55
ff_libmpeghdec_decoder
const FFCodec ff_libmpeghdec_decoder
Definition: libmpeghdec.c:217
NULL
#define NULL
Definition: coverity.c:32
MPEGH3DADecContext
Definition: libmpeghdec.c:46
AV_CH_LAYOUT_5POINT1
#define AV_CH_LAYOUT_5POINT1
Definition: channel_layout.h:228
mpegh3dadec_init
static av_cold int mpegh3dadec_init(AVCodecContext *avctx)
Definition: libmpeghdec.c:104
AV_CODEC_CAP_CHANNEL_CONF
#define AV_CODEC_CAP_CHANNEL_CONF
Codec should fill in channel configuration and samplerate instead of container.
Definition: codec.h:91
ff_get_buffer
int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
Get a buffer for a frame.
Definition: decode.c:1720
init
int(* init)(AVBSFContext *ctx)
Definition: dts2pts.c:368
AV_CODEC_CAP_DR1
#define AV_CODEC_CAP_DR1
Codec uses get_buffer() or get_encode_buffer() for allocating buffers and supports custom allocators.
Definition: codec.h:52
AVPacket::size
int size
Definition: packet.h:559
AVChannelLayout
An AVChannelLayout holds information about the channel layout of audio data.
Definition: channel_layout.h:319
codec_internal.h
AVCodecContext::sample_fmt
enum AVSampleFormat sample_fmt
audio sample format
Definition: avcodec.h:1031
frame.h
AVERROR_EXTERNAL
#define AVERROR_EXTERNAL
Generic error in an external library.
Definition: error.h:59
av_channel_layout_compare
int av_channel_layout_compare(const AVChannelLayout *chl, const AVChannelLayout *chl1)
Check whether two channel layouts are semantically the same, i.e.
Definition: channel_layout.c:809
layout
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel layout
Definition: filter_design.txt:18
AV_CH_LAYOUT_5POINT0
#define AV_CH_LAYOUT_5POINT0
Definition: channel_layout.h:227
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:256
AVPacket::pts
int64_t pts
Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will b...
Definition: packet.h:551
AVCodecContext::extradata
uint8_t * extradata
Out-of-band global headers that may be used by some codecs.
Definition: avcodec.h:514
av_malloc_array
#define av_malloc_array(a, b)
Definition: tableprint_vlc.h:32
AV_CH_LAYOUT_7POINT1
#define AV_CH_LAYOUT_7POINT1
Definition: channel_layout.h:240
AV_CH_LAYOUT_7POINT1_WIDE
#define AV_CH_LAYOUT_7POINT1_WIDE
Definition: channel_layout.h:241
MPEGH3DADecContext::decoder_buffer
int32_t * decoder_buffer
Definition: libmpeghdec.c:51
AVCodec::name
const char * name
Name of the codec implementation.
Definition: codec.h:179
CH_LAYOUT_7POINT2POINT3
#define CH_LAYOUT_7POINT2POINT3
ret
ret
Definition: filter_design.txt:187
frame
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several the filter must be ready for frames arriving randomly on any input any filter with several inputs will most likely require some kind of queuing mechanism It is perfectly acceptable to have a limited queue and to drop frames when the inputs are too unbalanced request_frame For filters that do not use the this method is called when a frame is wanted on an output For a it should directly call filter_frame on the corresponding output For a if there are queued frames already one of these frames should be pushed If the filter should request a frame on one of its repeatedly until at least one frame has been pushed Return or at least make progress towards producing a frame
Definition: filter_design.txt:265
AV_CH_LAYOUT_SURROUND
#define AV_CH_LAYOUT_SURROUND
Definition: channel_layout.h:221
AVCodecContext
main external API structure.
Definition: avcodec.h:431
CH_LAYOUT_7POINT1POINT6
#define CH_LAYOUT_7POINT1POINT6
channel_layout.h
AV_CH_LAYOUT_5POINT1POINT2
#define AV_CH_LAYOUT_5POINT1POINT2
Definition: channel_layout.h:243
mpegh3dadec_flush
static av_cold void mpegh3dadec_flush(AVCodecContext *avctx)
Definition: libmpeghdec.c:206
AV_CODEC_CAP_DELAY
#define AV_CODEC_CAP_DELAY
Encoder or decoder requires flushing with NULL input at the end in order to give the complete and cor...
Definition: codec.h:76
mem.h
AVPacket
This structure stores compressed data.
Definition: packet.h:535
AVCodecContext::priv_data
void * priv_data
Definition: avcodec.h:458
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
AV_CH_LAYOUT_4POINT0
#define AV_CH_LAYOUT_4POINT0
Definition: channel_layout.h:223
int32_t
int32_t
Definition: audioconvert.c:56
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
AVERROR_INVALIDDATA
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:61
AV_SAMPLE_FMT_S32
@ AV_SAMPLE_FMT_S32
signed 32 bits
Definition: samplefmt.h:59
AV_CH_LAYOUT_2_2
#define AV_CH_LAYOUT_2_2
Definition: channel_layout.h:225
PER_CHANNEL_OUTBUF_SIZE
#define PER_CHANNEL_OUTBUF_SIZE
Definition: libmpeghdec.c:44