这个问题已被问到很多,但没有代码对我有用。我已经能够在Android上播放用ffmpeg解码的文件,但它很吵,很吵。 我在使用最新的ffmpeg版本来解码mp3文件的书中找到了名为“linux sound programming”的书中的代码。 代码尝试将mp3文件解码为pcm,然后将其放入名为output的文件中。 我想要做的是动态解码字节并用Java发送到AudioTrack。
void JNICALL Java_com_example_home_hellondk_MainActivity_loadFile
(JNIEnv* env, jobject obj,jstring file,jbyteArray array)
{
jboolean isfilenameCopy;
const char * filename = (*env)->GetStringUTFChars(env, file,
&isfilenameCopy);
jclass cls = (*env)->GetObjectClass(env, obj);
jmethodID play = (*env)->GetMethodID(env, cls, "playSound", "([BI)V");
AVCodec *codec;
AVCodecContext *c= NULL;
int len;
FILE *f, *outfile;
uint8_t inbuf[AUDIO_INBUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE];
AVPacket avpkt;
AVFrame *decoded_frame = NULL;
AVFormatContext* container=NULL;
av_init_packet(&avpkt);
int num_streams = 0;
int sample_size = 0;
printf("Decode audio file %s \n", filename);
LOGE("Decode audio file %s\n", filename);
/* find the MPEG audio decoder */
/* codec = avcodec_find_decoder(AV_CODEC_ID_MP3);
if (!codec) {
fprintf(stderr, "Codec not found\n");
LOGE("Codec not found\n");
exit(1);
}*/
int lError;
if ((lError = avformat_open_input(&container, filename, NULL, NULL))
!= 0) {
LOGE("Error open source file: %d", lError);
exit(1);
}
if ((lError = avformat_find_stream_info(container,NULL)) < 0) {
LOGE("Error find stream information: %d", lError);
exit(1);
}
LOGE("Stage 1.5");
LOGE("audio format: %s", container->iformat->name);
LOGE("audio bitrate: %llu", container->bit_rate);
int stream_id = -1;
// To find the first audio stream. This process may not be necessary
// if you can gurarantee that the container contains only the desired
// audio stream
LOGE("nb_streams: %d", container->nb_streams);
int i;
for (i = 0; i < container->nb_streams; i++) {
if (container->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
stream_id = i;
LOGE("stream_id: %d", stream_id);
break;
}
}
AVCodecContext* codec_context = container->streams[stream_id]->codec;
codec = avcodec_find_decoder(codec_context->codec_id);
LOGE("stream_id: %d", stream_id);
LOGE("codec %s", codec->name);
if (!codec) {
fprintf(stderr, "codec not found\n");
exit(1);
}
c = avcodec_alloc_context3(codec);
if (!c) {
fprintf(stderr, "Could not allocate audio codec context\n");
LOGE("Could not allocate audio codec context\n");
exit(1);
}
/* open it */
if (avcodec_open2(c, codec, NULL) < 0) {
fprintf(stderr, "Could not open codec\n");
LOGE("Could not open codec\n");
exit(1);
}
f = fopen(filename, "rb");
if (!f) {
fprintf(stderr, "Could not open %s\n", filename);
LOGE("Could not open %s\n",filename);
exit(1);
}
const char *outfilename;
outfile = fopen(outfilename, "wb");
if (!outfile) {
av_free(c);
exit(1);
}
avpkt.data = inbuf;
avpkt.size = fread(inbuf, 1, AUDIO_INBUF_SIZE, f);
LOGE("Stage 5");
/* decode until eof */
while (avpkt.size > 0) {
int got_frame = 0;
if (!decoded_frame) {
if (!(decoded_frame = av_frame_alloc())) {
fprintf(stderr, "out of memory\n");
exit(1);
}
} else {
av_frame_unref(decoded_frame);
}
printf("Stream idx %d\n", avpkt.stream_index);
len = avcodec_decode_audio4(c, decoded_frame, &got_frame, &avpkt);
if (len < 0) {
fprintf(stderr, "Error while decoding\n");
exit(1);
}
if (got_frame) {
printf("Decoded frame nb_samples %d, format %d\n",
decoded_frame->nb_samples,
decoded_frame->format);
if (decoded_frame->data[1] != NULL)
printf("Data[1] not null\n");
else
printf("Data[1] is null\n");
/* if a frame has been decoded, output it */
int data_size = av_samples_get_buffer_size(NULL, c->channels,
decoded_frame->nb_samples,
c->sample_fmt, 1);
// first time: count the number of planar streams
if (num_streams == 0) {
while (num_streams < AV_NUM_DATA_POINTERS &&
decoded_frame->data[num_streams] != NULL)
num_streams++;
printf("Number of streams %d\n", num_streams);
}
// first time: set sample_size from 0 to e.g 2 for 16-bit data
if (sample_size == 0) {
sample_size =
data_size / (num_streams * decoded_frame->nb_samples);
}
int m, n;
for (n = 0; n < decoded_frame->nb_samples; n++) {
// interleave the samples from the planar streams
for (m = 0; m < num_streams; m++) {
fwrite(&decoded_frame->data[m][n*sample_size],
1, sample_size, outfile);
}
}
/* jbyte *bytes = (*env)->GetByteArrayElements(env, array, NULL);
memcpy(bytes, decoded_frame->data[1], data_size);
(*env)->ReleaseByteArrayElements(env, array, bytes, 0);
(*env)->CallVoidMethod(env, obj, play, array, data_size);
*/
}
avpkt.size -= len;
avpkt.data += len;
if (avpkt.size < AUDIO_REFILL_THRESH) {
/* Refill the input buffer, to avoid trying to decode
* incomplete frames. Instead of this, one could also use
* a parser, or use a proper container format through
* libavformat. */
memmove(inbuf, avpkt.data, avpkt.size);
avpkt.data = inbuf;
len = fread(avpkt.data + avpkt.size, 1,
AUDIO_INBUF_SIZE - avpkt.size, f);
if (len > 0)
avpkt.size += len;
}
}
fclose(f);
avcodec_free_context(&c);
av_frame_free(&decoded_frame);
}
解码的字节在本节中
fwrite(&decoded_frame->data[m][n*sample_size], 1, sample_size, outfile);
允许您向java发送字节的代码是:
jbyte *bytes = (*env)->GetByteArrayElements(env, array, NULL);
memcpy(bytes, decoded_frame->data[0], data_size);
(*env)->ReleaseByteArrayElements(env, array, bytes, 0);
(*env)->CallVoidMethod(env, obj, play, array, data_size);
我现在已经工作了一个多星期,没有任何对我有用。
提前感谢您的帮助