[MPlayer-dev-eng] Re: [PATCH] encoding audio with libavcodec

Tobias Diedrich ranma at gmx.at
Sun Nov 2 16:12:57 CET 2003


Nico wrote:

> but there are 2 problems with your patch:
> -  A/V sync is immediately lost in the case of ac3; I can see that it's 

Hmm I only checked mp3 and adpcm...

> due to this code:
> 
>    if (alavc_ctx->block_align)
>        mux_a->wf->nBlockAlign = alavc_ctx->block_align;
>    else
>        mux_a->wf->nBlockAlign = alavc_ctx->frame_size;
>
> in both cases (ac3 and mp2) alavc_ctx->block_align is 0, so 
> mux_a->wf->nBlockAlign ens up being 1152 for mp2 and
> 1536 for ac3; mp2 is in sync and ac3 not.

It would be nice to have some unambigous information about how to fill
these structures.
Some software seems to set nBlockalign to 1, other to the Same as
mp3.nBlockSize and the third to the number of samples in one block
(alavc_ctx->frame_size).  And Microsoft of course defines the fields as
to be "computed according to manufacturer's specification" if the format
tag is not pcm.  So it may very well be, that we really need different
cases for each format.

As far as I understand it now (I made a few more tests), nBlockAlign is
supposed to the size of the elementary blocks the codec can decode.
That only works for cbr though.
The MS imaadpcm codec sets mux_a->h.dwScale = mux_a->h.dwSampleSize =
mux_a->wf->nBlockAlign, which seems to work well for mp3 and ac3 too.

> 2) there's this assignment that I don't understand:
> 
> mux_a->wf->wBitsPerSample = 0;
> 
> shouldn't it be 16?

Well, it's zero on all my avis and I guess it does make sense because we
describe the compressed stream here.

Other things:
IMHO it would be more consistent to use -oac lavc instead of -oac alavc
and integrate the options into -lavcopts.
I also think that errors should be fatal, as it would not be nice to
find your batch encodes without audio...

Updated patch attached, I checked mp2, ac3 and adpcm_ima_wav, the latter
basically works, but sound is distorted a bit.
libavcodec uses a default block_align of 1024, where the ms ima adpcm
decoder expects 2048, so I changed that.  And there seems to be a bug in
libmpdemux/muxer_avi, it substracts 2 from cbSize if it is set
(Virtualdub complains about that in the mp3 case).

-- 
Tobias						PGP: http://9ac7e0bc.2ya.com
This mail is made of 100% recycled bits
-------------- next part --------------
Index: mencoder.c
===================================================================
RCS file: /cvsroot/mplayer/main/mencoder.c,v
retrieving revision 1.219
diff -u -r1.219 mencoder.c
--- mencoder.c	22 Oct 2003 17:04:15 -0000	1.219
+++ mencoder.c	2 Nov 2003 15:08:08 -0000
@@ -14,6 +14,7 @@
 #define ACODEC_PCM 1
 #define ACODEC_VBRMP3 2
 #define ACODEC_NULL 3
+#define ACODEC_LAVC 4
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -71,6 +72,21 @@
 
 #include "osdep/timer.h"
 
+#ifdef USE_LIBAVCODEC
+// for lavc audio encoding
+#include "libavcodec/avcodec.h"
+AVCodec        *lavc_acodec;
+AVCodecContext *lavc_actx = NULL;
+extern char    *lavc_param_acodec = "mp2";
+extern int      lavc_param_abitrate = 224;
+extern int      lavc_param_atag = 0x0;
+static int      alavc_ok = 0;
+// tmp buffer for lavc audio encoding (to free!!!!!)
+void *alavc_buf = NULL;
+
+uint32_t alavc_find_tag(char *codec);
+#endif
+
 int vo_doublebuffering=0;
 int vo_directrendering=0;
 int vo_config_count=0;
@@ -792,6 +808,141 @@
     }
     break;
 #endif
+#ifdef USE_LIBAVCODEC
+case ACODEC_LAVC:
+    if(! lavc_param_acodec)
+    {
+       mp_msg(MSGT_MENCODER, MSGL_FATAL, "Audio LAVC, Missing codec name!\n");
+       exit(1);
+    }
+
+    avcodec_init();
+    avcodec_register_all();
+
+    lavc_acodec = avcodec_find_encoder_by_name(lavc_param_acodec);
+    if (!lavc_acodec)
+    {
+       mp_msg(MSGT_MENCODER, MSGL_FATAL, "Audio LAVC, couldn't find encoder for codec %s\n", lavc_param_acodec);
+       exit(1);
+    }
+
+    lavc_actx = avcodec_alloc_context();
+    if(lavc_actx == NULL)
+    {
+       mp_msg(MSGT_MENCODER, MSGL_FATAL, "Audio LAVC, couldn't allocate context!\n");
+       exit(1);
+    }
+
+    if(lavc_param_atag == 0)
+        lavc_param_atag = alavc_find_tag(lavc_param_acodec);
+
+    // put sample parameters
+    lavc_actx->channels = audio_output_channels ? audio_output_channels : sh_audio->channels;
+    lavc_actx->sample_rate = force_srate ? force_srate : sh_audio->samplerate;
+    lavc_actx->bit_rate = lavc_param_abitrate * 1000;
+
+    /*
+     * Special case for imaadpcm.
+     * The bitrate is only dependant on samplerate.
+     * We have to known frame_size and block_align in advance,
+     * so I just copied the code from libavcodec/adpcm.c
+     *
+     * However, ms imaadpcm uses a block_align of 2048,
+     * lavc defaults to 1024
+     */
+    if(lavc_param_atag == 0x11) {
+        int blkalign = 2048;
+        int framesize = (blkalign - 4 * lavc_actx->channels) * 8 / (4 * lavc_actx->channels) + 1;
+        lavc_actx->bit_rate = lavc_actx->sample_rate*8*blkalign/framesize;
+    }
+
+    if(avcodec_open(lavc_actx, lavc_acodec) < 0)
+    {
+       mp_msg(MSGT_MENCODER, MSGL_FATAL, "Couldn't open codec %s, br=%d\n", lavc_param_acodec, lavc_param_abitrate);
+       exit(1);
+    }
+
+    if(lavc_param_atag == 0x11) {
+        lavc_actx->block_align = 2048;
+	lavc_actx->frame_size = (lavc_actx->block_align - 4 * lavc_actx->channels) * 8 / (4 * lavc_actx->channels) + 1;
+    }
+
+    alavc_buf = malloc(lavc_actx->frame_size * 2 * lavc_actx->channels);
+    if(alavc_buf == NULL)
+    {
+       fprintf(stderr, "Couldn't allocate %d bytes\n", lavc_actx->frame_size * 2 * lavc_actx->channels);
+       exit(1);
+    }
+
+    alavc_ok = 1;
+
+    if (sizeof(MPEGLAYER3WAVEFORMAT) != 30)
+       mp_msg(MSGT_MENCODER, MSGL_WARN,
+              "sizeof(MPEGLAYER3WAVEFORMAT)==%d!=30, maybe broken C compiler?\n",
+              sizeof(MPEGLAYER3WAVEFORMAT));
+
+    mux_a->wf = malloc(sizeof(MPEGLAYER3WAVEFORMAT));  // should be 30
+    mux_a->wf->wFormatTag = lavc_param_atag;
+    mux_a->wf->nChannels = lavc_actx->channels;
+    mux_a->wf->nSamplesPerSec = lavc_actx->sample_rate;
+    mux_a->wf->nAvgBytesPerSec = (lavc_actx->bit_rate / 8);
+    if (lavc_actx->block_align)
+        mux_a->wf->nBlockAlign = lavc_actx->block_align;
+    else
+        mux_a->wf->nBlockAlign = mux_a->wf->nAvgBytesPerSec * lavc_actx->frame_size / mux_a->wf->nSamplesPerSec; /* for cbr */
+
+    mux_a->h.dwRate = mux_a->wf->nAvgBytesPerSec;
+    mux_a->h.dwScale = mux_a->h.dwSampleSize = mux_a->wf->nBlockAlign;
+    mux_a->h.dwInitialFrames = 1;
+    mux_a->h.dwSuggestedBufferSize = mux_a->wf->nBlockAlign*(mux_a->wf->nAvgBytesPerSec/(2*mux_a->wf->nBlockAlign)); /* suggest BufferSize 0.5 seconds */
+
+    switch (lavc_param_atag) {
+    case 0x11: /* imaadpcm */
+        mux_a->wf->wBitsPerSample = 4;
+        mux_a->wf->cbSize = 2;
+        /*
+         * Magic imaadpcm values, currently probably only valid
+         * for 48KHz Stereo
+         */
+        ((unsigned char*)mux_a->wf)[sizeof(WAVEFORMATEX)] = 0xf9;
+        ((unsigned char*)mux_a->wf)[sizeof(WAVEFORMATEX)+1] = 0x07;
+        break;
+    case 0x55: /* mp2 or mp3 */
+        mux_a->wf->cbSize = 12;
+        mux_a->wf->wBitsPerSample = 0; /* does not apply */
+        ((MPEGLAYER3WAVEFORMAT *) (mux_a->wf))->wID = 1;
+        ((MPEGLAYER3WAVEFORMAT *) (mux_a->wf))->fdwFlags = 2;
+        ((MPEGLAYER3WAVEFORMAT *) (mux_a->wf))->nBlockSize = mux_a->wf->nAvgBytesPerSec * lavc_actx->frame_size / mux_a->wf->nSamplesPerSec;
+        ((MPEGLAYER3WAVEFORMAT *) (mux_a->wf))->nFramesPerBlock = 1;
+        ((MPEGLAYER3WAVEFORMAT *) (mux_a->wf))->nCodecDelay = 0;
+        break;
+    default:
+        mux_a->wf->cbSize = 0;
+        mux_a->wf->wBitsPerSample = 0; /* Unknown */
+        break;
+    }
+
+    // setup filter:
+    if (!init_audio_filters(
+       sh_audio,
+       sh_audio->samplerate, sh_audio->channels,
+       sh_audio->sample_format, sh_audio->samplesize,
+       mux_a->wf->nSamplesPerSec, mux_a->wf->nChannels,
+#ifdef WORDS_BIGENDIAN
+       AFMT_S16_BE, 2,
+#else
+       AFMT_S16_LE, 2,
+#endif
+       mux_a->h.dwSuggestedBufferSize,
+       mux_a->h.dwSuggestedBufferSize*2)) {
+        mp_msg(MSGT_CPLAYER, MSGL_ERR, "Couldn't find matching filter / ao format!\n");
+        exit(1);
+    }
+
+    mp_msg(MSGT_MENCODER, MSGL_V, "FRAME_SIZE: %d, BUFFER_SIZE: %d, TAG: 0x%x\n", lavc_actx->frame_size, lavc_actx->frame_size * 2 * lavc_actx->channels, mux_a->wf->wFormatTag);
+
+    break;
+#endif
 }
 
 if (verbose>1) print_wave_header(mux_a->wf);
@@ -932,6 +1083,25 @@
 		len=mux_a->h.dwSampleSize*(mux_a->h.dwRate/audio_density);
 		len=dec_audio(sh_audio,mux_a->buffer,len);
 		break;
+#ifdef USE_LIBAVCODEC
+            case ACODEC_LAVC:
+               {
+                       if(alavc_ok)
+                       {
+                               int  size, rd_len;
+
+                               size = lavc_actx->frame_size * 2 * mux_a->wf->nChannels;
+
+                               rd_len = dec_audio(sh_audio, alavc_buf, size);
+                               if(rd_len != size)
+                                       break;
+
+                               // Encode one frame
+                               len = avcodec_encode_audio(lavc_actx, &(mux_a->buffer[0]), size, alavc_buf);
+                       }
+               }
+               break;
+#endif
 	    }
 	} else {
 	    // VBR - encode/copy an audio frame
@@ -1294,6 +1464,11 @@
 if(demuxer) free_demuxer(demuxer);
 if(stream) free_stream(stream); // kill cache thread
 
+#ifdef USE_LIBAVCODEC
+if(alavc_buf != NULL)
+    free(alavc_buf);
+#endif
+
 return interrupted;
 }
 
@@ -1600,3 +1775,26 @@
 	mencoder_exit(0, NULL);
 }
 #endif
+
+#ifdef USE_LIBAVCODEC
+uint32_t alavc_find_tag(char *codec)
+{
+    if(codec == NULL)
+       return 0;
+
+    if(! strcasecmp(codec, "mp2"))
+       return 0x50;
+
+    if(! strcasecmp(codec, "mp3"))
+       return 0x55;
+
+    if(! strcasecmp(codec, "ac3"))
+       return 0x2000;
+
+    if(! strcasecmp(codec, "adpcm_ima_wav"))
+       return 0x11;
+
+    return 0;
+}
+#endif
+
Index: cfg-mencoder.h
===================================================================
RCS file: /cvsroot/mplayer/main/cfg-mencoder.h,v
retrieving revision 1.71
diff -u -r1.71 cfg-mencoder.h
--- cfg-mencoder.h	25 Oct 2003 18:44:41 -0000	1.71
+++ cfg-mencoder.h	2 Nov 2003 15:08:09 -0000
@@ -108,11 +108,19 @@
 #else
 	{"mp3lame", "MPlayer was compiled without libmp3lame support!\n", CONF_TYPE_PRINT, CONF_NOCFG, 0, 0, NULL},
 #endif
+#ifdef USE_LIBAVCODEC
+	{"lavc", &out_audio_codec, CONF_TYPE_FLAG, 0, 0, ACODEC_LAVC, NULL},
+#else
+	{"lavc", "MPlayer was compiled without libavcodec! See README or DOCS!\n", CONF_TYPE_PRINT, CONF_NOCFG, 0, 0, NULL},
+#endif
 	{"help", "\nAvailable codecs:\n"
 	"   copy     - frame copy, without re-encoding (useful for AC3)\n"
 	"   pcm      - uncompressed PCM audio\n"
 #ifdef HAVE_MP3LAME
 	"   mp3lame  - cbr/abr/vbr MP3 using libmp3lame\n"
+#endif
+#ifdef USE_LIBAVCODEC
+	"   lavc     - ffmpeg audio encoder (mp2, ac3, ...)\n"
 #endif
 	"\n", CONF_TYPE_PRINT, CONF_NOCFG, 0, 0, NULL},
 	{NULL, NULL, 0, 0, 0, 0, NULL}
Index: libmpcodecs/ve_lavc.c
===================================================================
RCS file: /cvsroot/mplayer/main/libmpcodecs/ve_lavc.c,v
retrieving revision 1.81
diff -u -r1.81 ve_lavc.c
--- libmpcodecs/ve_lavc.c	23 Oct 2003 12:05:33 -0000	1.81
+++ libmpcodecs/ve_lavc.c	2 Nov 2003 15:08:09 -0000
@@ -134,10 +134,17 @@
 static int lavc_param_cbp= 0;
 static int lavc_param_mv0= 0;
 
+char *lavc_param_acodec = "mp2";
+int lavc_param_atag = 0;
+int lavc_param_abitrate = 224;
+
 #include "m_option.h"
 
 #ifdef USE_LIBAVCODEC
 m_option_t lavcopts_conf[]={
+	{"acodec", &lavc_param_acodec, CONF_TYPE_STRING, 0, 0, 0, NULL},
+	{"abitrate", &lavc_param_abitrate, CONF_TYPE_INT, CONF_RANGE, 1, 1000, NULL},
+	{"atag", &lavc_param_atag, CONF_TYPE_INT, CONF_RANGE, 0, 0xffff, NULL},
 	{"vcodec", &lavc_param_vcodec, CONF_TYPE_STRING, 0, 0, 0, NULL},
 	{"vbitrate", &lavc_param_vbitrate, CONF_TYPE_INT, CONF_RANGE, 4, 24000000, NULL},
 	{"vratetol", &lavc_param_vrate_tolerance, CONF_TYPE_INT, CONF_RANGE, 4, 24000000, NULL},
Index: libmpdemux/muxer_avi.c
===================================================================
RCS file: /cvsroot/mplayer/main/libmpdemux/muxer_avi.c,v
retrieving revision 1.15
diff -u -r1.15 muxer_avi.c
--- libmpdemux/muxer_avi.c	19 Jan 2003 00:33:11 -0000	1.15
+++ libmpdemux/muxer_avi.c	2 Nov 2003 15:08:09 -0000
@@ -111,7 +111,7 @@
     if(s->h.dwSampleSize){
 	// CBR
 	s->h.dwLength+=len/s->h.dwSampleSize;
-	if(len%s->h.dwSampleSize) printf("Warning! len isn't divisable by samplesize!\n");
+	if(len%s->h.dwSampleSize) printf("Warning! len(%d) isn't divisable by samplesize(%d)!\n", len, s->h.dwSampleSize);
     } else {
 	// VBR
 	s->h.dwLength++;
@@ -136,7 +136,8 @@
 }
 
 // muxer->streams[i]->wf->cbSize
-#define WFSIZE(wf) (sizeof(WAVEFORMATEX)+(((wf)->cbSize)?((wf)->cbSize-2):0))
+// #define WFSIZE(wf) (sizeof(WAVEFORMATEX)+(((wf)->cbSize)?((wf)->cbSize-2):0))
+#define WFSIZE(wf) (sizeof(WAVEFORMATEX)+(wf)->cbSize)
 
 static void avifile_write_header(muxer_t *muxer){
   uint32_t riff[3];
Index: libavcodec/adpcm.c
===================================================================
RCS file: /cvsroot/ffmpeg/ffmpeg/libavcodec/adpcm.c,v
retrieving revision 1.15
diff -u -r1.15 adpcm.c
--- libavcodec/adpcm.c	26 Oct 2003 09:56:21 -0000	1.15
+++ libavcodec/adpcm.c	2 Nov 2003 15:08:11 -0000
@@ -42,7 +42,7 @@
  * readstr http://www.geocities.co.jp/Playtown/2004/
  */
 
-#define BLKSIZE 1024
+#define BLKSIZE 2048
 
 #define CLAMP_TO_SHORT(value) \
 if (value > 32767) \
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: Digital signature
URL: <http://lists.mplayerhq.hu/pipermail/mplayer-dev-eng/attachments/20031102/e5535657/attachment.pgp>


More information about the MPlayer-dev-eng mailing list