Ronald S. Bultje <[email protected]> added the comment:
Attached patch does the initialization of proper contexts for support of
WMAPro-in-WMAVoice. The actual decoding doesn't work yet because the
call to avcodec_decode_audio() is missing. Init fails though:
[wmapro @ 0x101855200] no length prefix
If you want to help, upload a sample of this file to
ftp://upload.ffmpeg.org/MPlayer/incoming/ and contact the ffmpeg-devel
mailing list.
basically, once done correctly, the proper thing to do is to use
ff_copy_bits() to re-align, then call the WMAPro decoder, count the
number of bits read and then go back into the WMAVoice decoder and
subtract that number of bits (not bytes) off of the bit context.
Shouldn't be too hard once I know what to do with the WMAPro decoder
init.
________________________________________________
FFmpeg issue tracker <[email protected]>
<https://roundup.ffmpeg.org/issue1912>
________________________________________________
Index: libavcodec/wmavoice.c
===================================================================
--- libavcodec/wmavoice.c (revision 26050)
+++ libavcodec/wmavoice.c (working copy)
@@ -38,6 +38,7 @@
#include "libavutil/lzo.h"
#include "avfft.h"
#include "fft.h"
+#include "wma.h"
#define MAX_BLOCKS 8 ///< maximum number of blocks per frame
#define MAX_LSPS 16 ///< maximum filter order
@@ -256,7 +257,7 @@
/**
* @}
* @defgroup post_filter Postfilter values
- * Varibales used for postfilter implementation, mostly history for
+ * Variables used for postfilter implementation, mostly history for
* smoothing and so on, and context variables for FFT/iFFT.
* @{
*/
@@ -283,7 +284,17 @@
///< synthesis
/**
* @}
+ * @defgroup wmapro_in_wmavoice values for supporting WMAPro-in-WMAVoice
+ * Codec context and related information for WMAPro-in-WMAVoice.
+ * @{
*/
+ AVCodecContext *proctx;
+ int pro_samples_per_frame; ///< (default) samples per WMAPro
(super)frame
+ int pro_spf_nbits; ///< number of bits coding for
samples-per-frame
+ ///< when customly specified in bitstream
+ /**
+ * @}
+ */
} WMAVoiceContext;
/**
@@ -1719,7 +1730,7 @@
{
WMAVoiceContext *s = ctx->priv_data;
GetBitContext *gb = &s->gb, s_gb;
- int n, res, n_samples = 480;
+ int n, res, n_samples, max_samples, is_speech_frame, spf_nbits, shl;
double lsps[MAX_FRAMES][MAX_LSPS];
const double *mean_lsf = s->lsps == 16 ?
wmavoice_mean_lsf16[s->lsp_def_mode] :
wmavoice_mean_lsf10[s->lsp_def_mode];
@@ -1741,22 +1752,80 @@
/* First bit is speech/music bit, it differentiates between WMAVoice
* speech samples (the actual codec) and WMAVoice music samples, which
- * are really WMAPro-in-WMAVoice-superframes. I've never seen those in
- * the wild yet. */
- if (!get_bits1(gb)) {
- av_log_missing_feature(ctx, "WMAPro-in-WMAVoice support", 1);
- return -1;
+ * are really WMAPro-in-WMAVoice-superframes. */
+ if (!(is_speech_frame = get_bits1(gb))) {
+ if (!s->pro_spf_nbits) {
+ AVCodec *pro;
+
+ s->pro_samples_per_frame = 1 <<
ff_wma_get_frame_len_bits(ctx->sample_rate,
+ 3,
AV_RL16(ctx->extradata + 14));
+ s->pro_spf_nbits = av_log2(s->pro_samples_per_frame >> 4);
+
+ /* open decoder on demand, because 1) it's usually not needed and
+ * 2) it will cause thread locking errors when doing it recursively
+ * from within _init(). */
+ if (!(pro = avcodec_find_decoder(CODEC_ID_WMAPRO))) {
+ av_log(ctx, AV_LOG_WARNING,
+ "WMAPro decoder not found, WMAPro-in-WMAVoice will not
work\n");
+ return -1;
+ } else {
+ /* init wmapro decoder */
+ if (!(s->proctx = avcodec_alloc_context())) {
+ av_log(ctx, AV_LOG_ERROR,
+ "Failed to allocate WMAPro-in-WMAVoice context\n");
+ return AVERROR(ENOMEM);
+ }
+ if ((res = avcodec_copy_context(s->proctx, ctx)) < 0) {
+ av_log(ctx, AV_LOG_ERROR,
+ "Failed to copy WMAVoice to WMAPro context\n");
+ av_free(s->proctx->extradata);
+ av_freep(&s->proctx);
+ return res;
+ }
+ s->proctx->codec_id = CODEC_ID_WMAPRO;
+ s->proctx->extradata_size = 18;
+
+ if ((res = avcodec_open(s->proctx, pro)) < 0) {
+ av_log(ctx, AV_LOG_ERROR,
+ "Failed to open WMAPro-in-WMAVoice decoder\n");
+ av_free(s->proctx->extradata);
+ av_freep(&s->proctx);
+ return res;
+ }
+ }
+ /* if no decoder was found, just skip these frames */
+ } else if (!s->proctx)
+ return -1;
+
+ max_samples = s->pro_samples_per_frame;
+ spf_nbits = s->pro_spf_nbits;
+ shl = 5;
+ } else {
+ max_samples = 480;
+ spf_nbits = 12;
+ shl = 0;
}
- /* (optional) nr. of samples in superframe; always <= 480 and >= 0 */
+ /* (optional) nr. of samples in superframe; always <= max_samples and >= 0
*/
if (get_bits1(gb)) {
- if ((n_samples = get_bits(gb, 12)) > 480) {
+ if ((n_samples = (get_bits(gb, spf_nbits) << shl)) > max_samples) {
av_log(ctx, AV_LOG_ERROR,
- "Superframe encodes >480 samples (%d), not allowed\n",
- n_samples);
+ "Superframe encodes >%d samples (%d), not allowed\n",
+ max_samples, n_samples);
return -1;
}
+ } else {
+ n_samples = max_samples;
}
+
+ if (!is_speech_frame) {
+ // FIXME call wmapro decoder here with remaining bits, and return here
+ // with the bits (not bytes!) parsed by the wmapro decoder
+
+ /* FIXMEs: for things like postfilter smoothing, history for sample
+ * synthesis and so on, we need to reset these every time when a
+ * switch in music-speech-mode has been made. */
+ } else {
/* Parse LSPs, if global for the superframe (can also be per-frame). */
if (s->has_residual_lsps) {
double prev_lsps[MAX_LSPS], a1[MAX_LSPS * 2], a2[MAX_LSPS * 2];
@@ -1809,9 +1878,6 @@
skip_bits(gb, 10 * (res + 1));
}
- /* Specify nr. of output samples */
- *data_size = n_samples * sizeof(float);
-
/* Update history */
memcpy(s->prev_lsps, lsps[2],
s->lsps * sizeof(*s->prev_lsps));
@@ -1822,7 +1888,11 @@
if (s->do_apf)
memmove(s->zero_exc_pf, &s->zero_exc_pf[MAX_SFRAMESIZE],
s->history_nsamples * sizeof(*s->zero_exc_pf));
+ }
+ /* Specify nr. of output samples */
+ *data_size = n_samples * sizeof(float);
+
return 0;
}
@@ -1987,6 +2057,11 @@
ff_dct_end(&s->dst);
}
+ if (s->proctx) {
+ av_free(s->proctx->extradata);
+ av_freep(&s->proctx);
+ }
+
return 0;
}