libav を使用して Android アプリを開発しており、以下のコードで 3gp をデコードしようとしています。
#define simbiLog(...) __android_log_print(ANDROID_LOG_DEBUG, "simbiose", __VA_ARGS__)
...
AVCodec *codec;
AVCodecContext *c = NULL;
int len;
FILE *infile, *outfile;
uint8_t inbuf[AUDIO_INBUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE];
AVPacket avpkt;
AVFrame *decoded_frame = NULL;
simbiLog("inbuf size: %d", sizeof(inbuf) / sizeof(inbuf[0]));
av_register_all();
av_init_packet(&avpkt);
codec = avcodec_find_decoder(AV_CODEC_ID_AMR_NB);
if (!codec) {
simbiLog("codec not found");
return ERROR;
}
c = avcodec_alloc_context3(codec);
if (!c) {
simbiLog("Could not allocate audio codec context");
return ERROR;
}
int open = avcodec_open2(c, codec, NULL);
if (open < 0) {
simbiLog("could not open codec %d", open);
return ERROR;
}
infile = fopen(inputPath, "rb");
if (!infile) {
simbiLog("could not open %s", inputPath);
return ERROR;
}
outfile = fopen(outputPath, "wb");
if (!outfile) {
simbiLog("could not open %s", outputPath);
return ERROR;
}
avpkt.data = inbuf;
avpkt.size = fread(inbuf, 1, AUDIO_INBUF_SIZE, infile);
int iterations = 0;
while (avpkt.size > 0) {
simbiLog("iteration %d", (++iterations));
simbiLog("avpkt.size %d avpkt.data %X", avpkt.size, avpkt.data);
int got_frame = 0;
if (!decoded_frame) {
if (!(decoded_frame = avcodec_alloc_frame())) {
simbiLog("out of memory");
return ERROR;
}
} else {
avcodec_get_frame_defaults(decoded_frame);
}
//below the error, but it isn't occur on first time, only in 4th loop interation
len = avcodec_decode_audio4(c, decoded_frame, &got_frame, &avpkt);
if (len < 0) {
simbiLog("Error while decoding error %d frame %d duration %d", len, got_frame, avpkt.duration);
return ERROR;
} else {
simbiLog("Decoding length %d frame %d duration %d", len, got_frame, avpkt.duration);
}
if (got_frame) {
int data_size = av_samples_get_buffer_size(NULL, c->channels, decoded_frame->nb_samples, c->sample_fmt, 1);
size_t* fwrite_size = fwrite(decoded_frame->data[0], 1, data_size, outfile);
simbiLog("fwrite returned %d", fwrite_size);
}
avpkt.size -= len;
avpkt.data += len;
if (avpkt.size < AUDIO_REFILL_THRESH) {
memmove(inbuf, avpkt.data, avpkt.size);
avpkt.data = inbuf;
len = fread(avpkt.data + avpkt.size, 1, AUDIO_INBUF_SIZE - avpkt.size, infile);
if (len > 0)
avpkt.size += len;
simbiLog("fread returned %d", len);
}
}
fclose(outfile);
fclose(infile);
avcodec_close(c);
av_free(c);
av_free(decoded_frame);
しかし、次のログとエラーが表示されます:
inbuf size: 20488
iteration 1
avpkt.size 3305 avpkt.data BEEED40C
Decoding length 13 frame 1 duration 0
fwrite returned 640
fread returned 0
iteration 2
avpkt.size 3292 avpkt.data BEEED40C
Decoding length 13 frame 1 duration 0
fwrite returned 640
fread returned 0
iteration 3
avpkt.size 3279 avpkt.data BEEED40C
Decoding length 14 frame 1 duration 0
fwrite returned 640
fread returned 0
iteration 4
avpkt.size 3265 avpkt.data BEEED40C
Error while decoding error -1052488119 frame 0 duration 0
デコードしようとしているオーディオ ファイル:
$ avprobe blue.3gp
avprobe version 0.8.6-6:0.8.6-1ubuntu2, Copyright (c) 2007-2013 the Libav developers
built on Mar 30 2013 22:23:21 with gcc 4.7.2
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'blue.3gp':
Metadata:
major_brand : 3gp4
minor_version : 0
compatible_brands: isom3gp4
creation_time : 2013-09-19 18:53:38
Duration: 00:00:01.52, start: 0.000000, bitrate: 17 kb/s
Stream #0.0(eng): Audio: amrnb, 8000 Hz, 1 channels, flt, 12 kb/s
Metadata:
creation_time : 2013-09-19 18:53:38
どうもありがとう!
編集済み
次のメソッドに関するffmperのドキュメントを読みましたavcodec_decode_audio4
:
@warning The input buffer, avpkt->data must be FF_INPUT_BUFFER_PADDING_SIZE larger than the actual read bytes because some optimized bitstream readers read 32 or 64 bits at once and could read over the end.
@note You might have to align the input buffer. The alignment requirements depend on the CPU and the decoder.
そして、私はここで を使用した解決策を見てposix_memalign
、アンドロイドに と呼ばれる同様のメソッドを設立したmemalign
ので、変更を加えました:
削除:
uint8_t inbuf[AUDIO_INBUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE];
挿入:
int inbufSize = sizeof(uint8_t) * (AUDIO_INBUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE);
uint8_t *inbuf = memalign(FF_INPUT_BUFFER_PADDING_SIZE, inbufSize);
simbiLog("inbuf size: %d", inbufSize);
for (; inbufSize >= 0; inbufSize--)
simbiLog("inbuf position: %d index: %p", inbufSize, &inbuf[inbufSize]);
正しいメモリ シーケンス位置を取得していますが、エラーは変わりません。
出力の一部:
inbuf position: 37 index: 0x4e43d745
inbuf position: 36 index: 0x4e43d744
inbuf position: 35 index: 0x4e43d743
inbuf position: 34 index: 0x4e43d742
inbuf position: 33 index: 0x4e43d741
inbuf position: 32 index: 0x4e43d740
inbuf position: 31 index: 0x4e43d73f
inbuf position: 30 index: 0x4e43d73e
inbuf position: 29 index: 0x4e43d73d
inbuf position: 28 index: 0x4e43d73c
inbuf position: 27 index: 0x4e43d73b
inbuf position: 26 index: 0x4e43d73a
inbuf position: 25 index: 0x4e43d739
inbuf position: 24 index: 0x4e43d738
inbuf position: 23 index: 0x4e43d737
inbuf position: 22 index: 0x4e43d736
inbuf position: 21 index: 0x4e43d735
inbuf position: 20 index: 0x4e43d734
inbuf position: 19 index: 0x4e43d733