/* * Copyright (C) 2020-2024 ArtInChip Technology Co. Ltd * * SPDX-License-Identifier: Apache-2.0 * * Author: * Desc: decoder test demo */ #include "avcodec.h" #include #include #include #include #include #include #define FFMPEG_OUT_BUF_SIZE (70 * 1024) #define FFMPEG_WMA_WAV_LEN (28) #define FFMPEG_WMA_EXTRA_OFF (18) #define TEST_WMA_SAMPLE1 typedef struct ffmpeg_decoder_handle { AVCodec *codec; AVCodecContext *actx; } ffmpeg_decoder_handle; /*WAVEFORMATEX structure*/ #ifdef TEST_WMA_SAMPLE1 #define FFMPEG_IN_BUF_SIZE (0x02E7) static unsigned char g_extend_data[FFMPEG_WMA_WAV_LEN] = { 0x61, 0x01, 0x02, 0x00, // codec_id + channels 0x44, 0xAC, 0x00, 0x00, // sample_rate 0x80, 0x3E, 0x00, 0x00, // bit_rate 0xE7, 0x02, 0x10, 0x00, // block_align + bits_per_sample 0x0A, 0x00, 0x00, 0x00, // extra_size 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 }; #else #define FFMPEG_IN_BUF_SIZE (0x0600) static unsigned char g_extend_data[FFMPEG_WMA_WAV_LEN] = { 0x61, 0x01, 0x02, 0x00, // codec_id + channels 0x00, 0x7D, 0x00, 0x00, // sample_rate 0xA0, 0x0F, 0x00, 0x00, // bit_rate 0x00, 0x06, 0x10, 0x00, // block_align + bits_per_sample 0x0A, 0x00, 0x00, 0x88, // extra_size 0x00, 0x00, 0x17, 0x00, //0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 }; #endif /*Initial wma media info by file, this info may be parase by libavformat*/ static void ffmpeg_params_init(AVCodecContext *actx, enum AVCodecID codec_id) { if (!actx) { printf("actx is null.\n"); return; } /* This data read from wma file */ actx->codec_id = codec_id; actx->codec_tag = 0x1061; //2byte - 0x0161 #ifdef TEST_WMA_SAMPLE1 actx->channels = 2; //2byte - 0x0002 actx->sample_rate = 44100; //4byte - 0x0000AC44 actx->bit_rate = 16000 * 8; //4byte - 0x00003E80 actx->block_align = FFMPEG_IN_BUF_SIZE; //2byte - 0x02E7 actx->bits_per_sample = 16; //2byte - 0x0010 actx->extradata_size = 0xA; //2Byte - 0x000A; #else actx->channels = 2; //2byte - 0x0002 actx->sample_rate = 32000; //4byte - 0x00007D00 actx->bit_rate = 4000 * 8; //4byte - 0x0000FA0 actx->block_align = FFMPEG_IN_BUF_SIZE; //2byte - 0x0600 actx->bits_per_sample = 16; //2byte - 0x0010 actx->extradata_size = 0xA; //2Byte - 0x000A; #endif actx->extradata = &g_extend_data[FFMPEG_WMA_EXTRA_OFF]; } static ffmpeg_decoder_handle *ffmpeg_create_decoder(enum AVCodecID codec_id) { int ret; ffmpeg_decoder_handle *h_decoder = av_malloc(sizeof(ffmpeg_decoder_handle)); if (!h_decoder) return NULL; avcodec_register_all(); h_decoder->actx = avcodec_alloc_context(); if (!h_decoder->actx) { printf("avcodec_alloc_context failed.\n"); return NULL; } ffmpeg_params_init(h_decoder->actx, codec_id); h_decoder->codec = avcodec_find_decoder(codec_id); if (!h_decoder->codec) { av_log(h_decoder->actx, AV_LOG_ERROR, "avcodec_find_decoder failed\n"); return NULL; } ret = avcodec_open(h_decoder->actx, h_decoder->codec); if (ret) { av_log(h_decoder->actx, AV_LOG_ERROR, "avcodec_open failed %d.\n", ret); return NULL; } return h_decoder; } static int ffmpeg_decoder_decode(ffmpeg_decoder_handle *h_decoder, unsigned char *in_buf, int in_size, unsigned char *out_buf) { if (!h_decoder || !h_decoder->actx) return -1; int ret, got_frame = 0; AVFrame av_frame = {0}; struct AVPacket avpkt = {0}; av_frame.data[0] = out_buf; av_frame.frame_size = 0; avpkt.data = in_buf; avpkt.size = in_size; ret = avcodec_decode_audio(h_decoder->actx, &av_frame, &got_frame, &avpkt); if (ret < 0) { av_log(h_decoder->actx, AV_LOG_ERROR, "avcodec_decode_audio failed %d.\n", ret); return -1; } if (h_decoder->actx->frame_number % 50 == 0) { av_log(h_decoder->actx, AV_LOG_INFO, "decode ret(%d), nb_samples %d, frame_size %d, frame_number %d, got_frame %d.\n", ret, av_frame.nb_samples, av_frame.frame_size, h_decoder->actx->frame_number, got_frame); av_log(h_decoder->actx, AV_LOG_INFO, "pcm head data: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x.\n", out_buf[0], out_buf[1], out_buf[2], out_buf[3], out_buf[4], out_buf[5], out_buf[6], out_buf[7], out_buf[8], out_buf[9], out_buf[10], out_buf[11], out_buf[12], out_buf[12], out_buf[14], out_buf[15]); av_log(h_decoder->actx, AV_LOG_INFO, "pcm tail data: %x %x %x %x %x %x %x %x.\n", out_buf[av_frame.frame_size - 8], out_buf[av_frame.frame_size - 7], out_buf[av_frame.frame_size - 6], out_buf[av_frame.frame_size - 5], out_buf[av_frame.frame_size - 4], out_buf[av_frame.frame_size - 3], out_buf[av_frame.frame_size - 2], out_buf[av_frame.frame_size - 1]); } if (!got_frame) return 0; return (av_frame.frame_size); } static void ffmpeg_destroy_decoder(ffmpeg_decoder_handle *h_decoder) { if (!h_decoder) return; if (h_decoder->actx) { avcodec_free_context(&h_decoder->actx); h_decoder->codec = NULL; } av_free(h_decoder); } static int ffmpeg_decoder_demo(int argc, char *argv[]) { int i = 0, loop_cnt; int in_size, out_size, file_size; unsigned char *in_buf, *out_buf; unsigned int frame_size_total, frame_size_1s; FILE *fin_file, *fout_file; ffmpeg_decoder_handle *h_decoder; struct stat file_stat; if (argc != 3) { printf("Usage: %s in_file.dat out_file.pcm\n", argv[0]); return -1; } if(stat(argv[1], &file_stat) != 0) return -1; else file_size = file_stat.st_size; if ((fin_file = fopen(argv[1], "rb")) == NULL) { printf("ERROR: opening %s for infile\n", argv[1]); return -1; } if ((fout_file = fopen(argv[2], "wb")) == NULL) { printf("ERROR: opening %s for output\n", argv[2]); fclose(fin_file); return -1; } in_size = FFMPEG_IN_BUF_SIZE; in_buf = malloc(in_size); out_buf = malloc(FFMPEG_OUT_BUF_SIZE); h_decoder = ffmpeg_create_decoder(AV_CODEC_ID_WMAV2); if (!h_decoder) { printf("create decoder failed\n"); goto exit; } frame_size_total = 0; frame_size_1s = h_decoder->actx->sample_rate * h_decoder->actx->bits_per_sample * h_decoder->actx->channels / 8; loop_cnt = file_size / in_size; for (i = 0; i < loop_cnt; i++) { fread(in_buf, 1, in_size, fin_file); out_size = ffmpeg_decoder_decode(h_decoder, in_buf, in_size, out_buf); if (out_size > 0) { fwrite(out_buf, 1, out_size, fout_file); frame_size_total += out_size; } } av_log(h_decoder->actx, AV_LOG_INFO, "decode total_frame_count %d, total_time %d s.\n", h_decoder->actx->frame_number, frame_size_total / frame_size_1s); ffmpeg_destroy_decoder(h_decoder); exit: if (fin_file) fclose(fin_file); if (fout_file) fclose(fout_file); if (in_buf) free(in_buf); if (out_buf) free(out_buf); return 0; } MSH_CMD_EXPORT(ffmpeg_decoder_demo, ffmpeg decoder test);