AOSPにあるオープンソースなソニー製のLDACエンコーダ libldac を使ってみました。
ソースコードはgithubに置いときました。 https://github.com/eggman/ldacenc
libldac の コンパイル
- 普通のMakefileが無いので、普通にコンパイルして静的ライブラリを作ります。
$ git clone https://android.googlesource.com/platform/external/libldac
$ cd libldac/src
$ gcc -O2 -Werror -I../inc -c ldaclib.c
$ gcc -O2 -Werror -I../inc -c ldacBT.c
$ ar rcs libldacBT_enc.a ldaclib.o ldacBT.o
- macbookでコンパイルした場合のサイズ
$ size libldacBT_enc.a
__TEXT __DATA __OBJC others dec hex
36292 192 0 1120 37604 92e4 libldacBT_enc.a(ldaclib.o)
7134 0 0 480 7614 1dbe libldacBT_enc.a(ldacBT.o)
libldac の API
- APIは ldacBT.h に定義してあります。
- このヘッダファイルには親切な感じで使い方の記載があります。
LDACBT_API HANDLE_LDAC_BT ldacBT_get_handle( void );
LDACBT_API void ldacBT_free_handle( HANDLE_LDAC_BT hLdacBt );
LDACBT_API void ldacBT_close_handle( HANDLE_LDAC_BT hLdacBt );
LDACBT_API int ldacBT_get_version( void );
LDACBT_API int ldacBT_get_sampling_freq( HANDLE_LDAC_BT hLdacBt );
LDACBT_API int ldacBT_get_bitrate( HANDLE_LDAC_BT hLdacBt );
LDACBT_API int ldacBT_init_handle_encode( HANDLE_LDAC_BT hLdacBt, int mtu, int eqmid, int cm,
LDACBT_SMPL_FMT_T fmt, int sf );
LDACBT_API int ldacBT_set_eqmid( HANDLE_LDAC_BT hLdacBt, int eqmid );
LDACBT_API int ldacBT_get_eqmid( HANDLE_LDAC_BT hLdacBt );
LDACBT_API int ldacBT_alter_eqmid_priority( HANDLE_LDAC_BT hLdacBt, int priority );
LDACBT_API int ldacBT_encode( HANDLE_LDAC_BT hLdacBt, void *p_pcm, int *pcm_used,
unsigned char *p_stream, int *stream_sz, int *frame_num );
LDACBT_API int ldacBT_get_error_code( HANDLE_LDAC_BT hLdacBt );
- ストリームのエンコード開始後に、ldacBT_set_eqmid()のemqidを設定することでeqmidに対応したビットレートを動的に変更できます。
Initialize
- 初期化のサンプルコード
#include <stdio.h>
#include "ldacBT.h"
int main(void)
{
HANDLE_LDAC_BT h;
int ret, err;
h = ldacBT_get_handle();
printf("version %08x\n",ldacBT_get_version());
ret = ldacBT_init_handle_encode(h, 679, LDACBT_EQMID_HQ, LDACBT_CHANNEL_MODE_STEREO, LDACBT_SMPL_FMT_S24, 96000);
err=ldacBT_get_error_code(h);
printf("ret=%d api_error=%d\n", ret, LDACBT_API_ERR(err));
printf("sampling_freq %08x\n",ldacBT_get_sampling_freq(h));
printf("bit_rate %08x\n",ldacBT_get_bitrate(h));
return 0;
}
- 実行例
version 00020002
ret=0 api_error=0
sampling_freq 00017700
bit_rate 000003de
Encode
- 256サンプルをencodeする。
- 128サンプルだと何も出力されませんでした。
- 256サンプルを入力すると、660バイトのエンコードデータが得られました。
#include <stdio.h>
#include "ldacBT.h"
int main(void)
{
HANDLE_LDAC_BT h;
int ret, err, pcm_used, ldac_stream_size, ldac_frame_num;
unsigned char pcm[256*2*2]; /* 256 samples * 2ch * 16bit */
unsigned char ldac[1024];
h = ldacBT_get_handle();
ret = ldacBT_init_handle_encode(h, 679, LDACBT_EQMID_HQ, LDACBT_CHANNEL_MODE_STEREO, LDACBT_SMPL_FMT_S16, 48000);
err=ldacBT_get_error_code(h);
printf("ret=%d api_error=%d handle_error=%d block_error=%d\n", ret, LDACBT_API_ERR(err), LDACBT_HANDLE_ERR(err), LDACBT_BLOCK_ERR(err));
ret = ldacBT_encode(h, pcm, &pcm_used, ldac, &ldac_stream_size, &ldac_frame_num);
err=ldacBT_get_error_code(h);
printf("ret=%d api_error=%d handle_error=%d block_error=%d\n", ret, LDACBT_API_ERR(err), LDACBT_HANDLE_ERR(err), LDACBT_BLOCK_ERR(err));
printf(" pcm_used=%d ldac_stream_size=%d ldac_frame_num=%d\n", pcm_used, ldac_stream_size, ldac_frame_num);
ret = ldacBT_encode(h, &pcm[128*2*2], &pcm_used, ldac, &ldac_stream_size, &ldac_frame_num);
err=ldacBT_get_error_code(h);
printf("ret=%d api_error=%d handle_error=%d block_error=%d\n", ret, LDACBT_API_ERR(err), LDACBT_HANDLE_ERR(err), LDACBT_BLOCK_ERR(err));
printf(" pcm_used=%d ldac_stream_size=%d ldac_frame_num=%d\n", pcm_used, ldac_stream_size, ldac_frame_num);
return 0;
}
- 実行例
ret=0 api_error=0 handle_error=0 block_error=0
ret=0 api_error=0 handle_error=0 block_error=0
pcm_used=512 ldac_stream_size=0 ldac_frame_num=0
ret=0 api_error=0 handle_error=0 block_error=0
pcm_used=512 ldac_stream_size=660 ldac_frame_num=2
Encode wav file
- 16bit stereo な wavファイルを読み込んでエンコードして出力します。
- ファイルの最後の端数の部分はエンコードされません。
#include <stdio.h>
#include "ldacBT.h"
int main(int argc, char *argv[])
{
HANDLE_LDAC_BT h;
int ret, err, pcm_used, ldac_stream_size, ldac_frame_num;
unsigned char pcm[128*2*2];
unsigned char ldac[1024];
FILE *infp, *outfp;
unsigned char header[44];
if ((infp = fopen(argv[1], "r"))==NULL) {
printf("can't open input file\n");
return -1;
}
if ((outfp = fopen(argv[2], "w"))==NULL) {
printf("can't open output file\n");
return -1;
}
//skip wave header
fread(header, 44, 1, infp);
h = ldacBT_get_handle();
ret = ldacBT_init_handle_encode(h, 679, LDACBT_EQMID_HQ, LDACBT_CHANNEL_MODE_STEREO, LDACBT_SMPL_FMT_S16, 48000);
while(fread(pcm, 512, 1, infp))
{
ret = ldacBT_encode(h, &pcm[0], &pcm_used, ldac, &ldac_stream_size, &ldac_frame_num);
printf(" pcm_used=%d ldac_stream_size=%d ldac_frame_num=%d\n", pcm_used, ldac_stream_size, ldac_frame_num);
fwrite(ldac, 1, ldac_stream_size, outfp);
}
ldacBT_close_handle(h);
return 0;
}
- 実行例
$./ldacenc 1kHz-0-dither.wav 1khz.ldac_hq
pcm_used=512 ldac_stream_size=0 ldac_frame_num=0
pcm_used=512 ldac_stream_size=660 ldac_frame_num=2
pcm_used=512 ldac_stream_size=0 ldac_frame_num=0
pcm_used=512 ldac_stream_size=660 ldac_frame_num=2
pcm_used=512 ldac_stream_size=0 ldac_frame_num=0
pcm_used=512 ldac_stream_size=660 ldac_frame_num=2
- サイズ
- HQ、SQ、MQでエンコードした場合のサイズです。 それぞれ990kbps, 660kbps, 330kbpsになっています。
2880044 1kHz-0-dither.wav
1855920 1khz.ldac_hq
1237500 1khz.ldac_sq
618420 1khz.ldac_mq