|
@@ -1,4 +1,4 @@
|
|
|
-
|
|
|
+
|
|
|
/**
|
|
|
* 叶海辉
|
|
|
* QQ群121376426
|
|
@@ -28,9 +28,6 @@ ReadAudioFileThread::ReadAudioFileThread()
|
|
|
{
|
|
|
mAudioCallBack = nullptr;
|
|
|
|
|
|
- mAACReader = new AACReader();
|
|
|
- mAudioDecoder = new AudioDecoder();
|
|
|
-
|
|
|
#if 1
|
|
|
mAudioPlayer = new AudioPlayer_RtAudio();
|
|
|
#else
|
|
@@ -48,9 +45,9 @@ std::list<AudioDevice> ReadAudioFileThread::getAudiDeviceList()
|
|
|
return mAudioPlayer->getAudiDeviceList();
|
|
|
}
|
|
|
|
|
|
-void ReadAudioFileThread::startRead(char* filePath)
|
|
|
+void ReadAudioFileThread::startRead(const std::string &filePath)
|
|
|
{
|
|
|
- strcpy(mFileName, filePath);
|
|
|
+ mFilePath = filePath;
|
|
|
|
|
|
//启动新的线程实现读取视频文件
|
|
|
std::thread([&](ReadAudioFileThread *pointer)
|
|
@@ -62,16 +59,9 @@ void ReadAudioFileThread::startRead(char* filePath)
|
|
|
|
|
|
void ReadAudioFileThread::run()
|
|
|
{
|
|
|
+// mIsReadThreadFinished = false;
|
|
|
+// mIsReadFinished = false;
|
|
|
|
|
|
- char *fileName = mFileName;
|
|
|
- FILE *fp = fopen(fileName, "rb");
|
|
|
- if (fp == nullptr)
|
|
|
- {
|
|
|
- fprintf(stderr, "AAC file not exist! \n");
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- mAudioDecoder->openDecoder();
|
|
|
mAudioPlayer->startPlay();
|
|
|
|
|
|
int totalFrameNum = 0; //总帧数
|
|
@@ -79,145 +69,571 @@ void ReadAudioFileThread::run()
|
|
|
uint32_t totalTime = 0; //总时长(毫秒)
|
|
|
uint32_t currentTime = 0; //当前播放时间(毫秒)
|
|
|
|
|
|
- ///获取音频强度数据,用于绘制波形图
|
|
|
- {
|
|
|
- std::list<float> mLeftChannelDbValues;
|
|
|
- std::list<float> mRighttChannelDbValues;
|
|
|
+ const char * file_path = mFilePath.c_str();
|
|
|
|
|
|
- while(!feof(fp))
|
|
|
- {
|
|
|
- char buf[10240];
|
|
|
- int size = fread(buf, 1, 1024, fp);//从h264文件读1024个字节 (模拟从网络收到h264流)
|
|
|
- int nCount = mAACReader->inputAACData((uint8_t*)buf,size);
|
|
|
+ pFormatCtx = nullptr;
|
|
|
+ pCodecCtx = nullptr;
|
|
|
+ pCodec = nullptr;
|
|
|
|
|
|
- while(1)
|
|
|
- {
|
|
|
- //从前面读到的数据中获取一个nalu
|
|
|
- AACFramePtr framePtr = mAACReader->getNextFrame();
|
|
|
- if (framePtr == nullptr || framePtr.get() == nullptr) break;
|
|
|
+ aCodecCtx = nullptr;
|
|
|
+ aCodec = nullptr;
|
|
|
+ aFrame = nullptr;
|
|
|
|
|
|
- AACFrame *aacFrame = framePtr.get();
|
|
|
+ mAudioStream = nullptr;
|
|
|
+ mVideoStream = nullptr;
|
|
|
|
|
|
- PCMFramePtr pcmFramePtr = mAudioDecoder->decode(aacFrame->getBuffer(), aacFrame->getSize());
|
|
|
+ audio_clock = 0;
|
|
|
+ video_clock = 0;
|
|
|
|
|
|
- PCMTYPE *buffer = (PCMTYPE *)pcmFramePtr->getBuffer();
|
|
|
+ int audioStream ,videoStream;
|
|
|
|
|
|
- /// 这里直接使用前两个字节转成short,然后作为纵坐标来绘制波形图。
|
|
|
- /// PS:这里的PCM音频数据排列方式为,左右左右左右左右...
|
|
|
- mLeftChannelDbValues.push_back(buffer[0] * 1.0 / MAXPCMVALUE);
|
|
|
- mRighttChannelDbValues.push_back(buffer[1] * 1.0 / MAXPCMVALUE);
|
|
|
+ //Allocate an AVFormatContext.
|
|
|
+ pFormatCtx = avformat_alloc_context();
|
|
|
|
|
|
- totalFrameNum++;
|
|
|
- }
|
|
|
+ if (avformat_open_input(&pFormatCtx, file_path, nullptr, nullptr) != 0)
|
|
|
+ {
|
|
|
+ fprintf(stderr, "can't open the file. \n");
|
|
|
+// doOpenVideoFileFailed();
|
|
|
+ goto end;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (avformat_find_stream_info(pFormatCtx, nullptr) < 0)
|
|
|
+ {
|
|
|
+ fprintf(stderr, "Could't find stream infomation.\n");
|
|
|
+// doOpenVideoFileFailed();
|
|
|
+ goto end;
|
|
|
+ }
|
|
|
+
|
|
|
+ videoStream = -1;
|
|
|
+ audioStream = -1;
|
|
|
+
|
|
|
+ ///循环查找视频中包含的流信息,
|
|
|
+ for (int i = 0; i < pFormatCtx->nb_streams; i++)
|
|
|
+ {
|
|
|
+ if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
|
|
|
+ {
|
|
|
+ videoStream = i;
|
|
|
+ }
|
|
|
+ if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO && audioStream < 0)
|
|
|
+ {
|
|
|
+ audioStream = i;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+// doTotalTimeChanged(getTotalTime());
|
|
|
+
|
|
|
+ ///打开视频解码器,并启动视频线程
|
|
|
+ if (videoStream >= 0)
|
|
|
+ {
|
|
|
+ ///查找视频解码器
|
|
|
+ pCodecCtx = pFormatCtx->streams[videoStream]->codec;
|
|
|
+ pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
|
|
|
+
|
|
|
+ if (pCodec == nullptr)
|
|
|
+ {
|
|
|
+ fprintf(stderr, "PCodec not found.\n");
|
|
|
+// doOpenVideoFileFailed();
|
|
|
+ goto end;
|
|
|
}
|
|
|
|
|
|
- if (mAudioCallBack != nullptr)
|
|
|
+ ///打开视频解码器
|
|
|
+ if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0)
|
|
|
{
|
|
|
- mAudioCallBack->onGetPcmWaveValues(mLeftChannelDbValues, mRighttChannelDbValues);
|
|
|
+ fprintf(stderr, "Could not open video codec.\n");
|
|
|
+// doOpenVideoFileFailed();
|
|
|
+ goto end;
|
|
|
}
|
|
|
|
|
|
- fseek(fp, 0, SEEK_SET);
|
|
|
+ mVideoStream = pFormatCtx->streams[videoStream];
|
|
|
}
|
|
|
|
|
|
- ///计算总时长
|
|
|
+ if (audioStream >= 0)
|
|
|
{
|
|
|
- /// 这里一帧音频的采样是1024,音频的采样率是一秒钟44100次,总时长便很容易就算。
|
|
|
- /// 当然也可以通过直接计算数据总大小,原理都是类似。
|
|
|
- totalTime = totalFrameNum * 1024.0 / 44100 * 1000; //单位是毫秒
|
|
|
+ ///查找音频解码器
|
|
|
+ aCodecCtx = pFormatCtx->streams[audioStream]->codec;
|
|
|
+ aCodec = avcodec_find_decoder(aCodecCtx->codec_id);
|
|
|
+
|
|
|
+ if (aCodec == NULL)
|
|
|
+ {
|
|
|
+ fprintf(stderr, "ACodec not found.\n");
|
|
|
+ audioStream = -1;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ ///打开音频解码器
|
|
|
+ if (avcodec_open2(aCodecCtx, aCodec, nullptr) < 0)
|
|
|
+ {
|
|
|
+ fprintf(stderr, "Could not open audio codec.\n");
|
|
|
+// doOpenVideoFileFailed();
|
|
|
+ goto end;
|
|
|
+ }
|
|
|
+
|
|
|
+ ///解码音频相关
|
|
|
+ aFrame = av_frame_alloc();
|
|
|
+
|
|
|
+
|
|
|
+ //重采样设置选项-----------------------------------------------------------start
|
|
|
+ aFrame_ReSample = nullptr;
|
|
|
+
|
|
|
+ //frame->16bit 44100 PCM 统一音频采样格式与采样率
|
|
|
+ swrCtx = nullptr;
|
|
|
+
|
|
|
+ //输入的声道布局
|
|
|
+ int in_ch_layout;
|
|
|
+
|
|
|
+ //输出的声道布局
|
|
|
+ int out_ch_layout = av_get_default_channel_layout(audio_tgt_channels); ///AV_CH_LAYOUT_STEREO
|
|
|
+
|
|
|
+ out_ch_layout &= ~AV_CH_LAYOUT_STEREO_DOWNMIX;
|
|
|
+
|
|
|
+ /// 这里音频播放使用了固定的参数
|
|
|
+ /// 强制将音频重采样成44100 双声道 AV_SAMPLE_FMT_S16
|
|
|
+ /// SDL播放中也是用了同样的播放参数
|
|
|
+ //重采样设置选项----------------
|
|
|
+ //输入的采样格式
|
|
|
+ in_sample_fmt = aCodecCtx->sample_fmt;
|
|
|
+ //输出的采样格式 16bit PCM
|
|
|
+ out_sample_fmt = AV_SAMPLE_FMT_S16;
|
|
|
+ //输入的采样率
|
|
|
+ in_sample_rate = aCodecCtx->sample_rate;
|
|
|
+ //输入的声道布局
|
|
|
+ in_ch_layout = aCodecCtx->channel_layout;
|
|
|
+
|
|
|
+ //输出的采样率
|
|
|
+ out_sample_rate = 44100;
|
|
|
+ //输出的声道布局
|
|
|
+
|
|
|
+ audio_tgt_channels = 2; ///av_get_channel_layout_nb_channels(out_ch_layout);
|
|
|
+ out_ch_layout = av_get_default_channel_layout(audio_tgt_channels); ///AV_CH_LAYOUT_STEREO
|
|
|
+
|
|
|
+ out_ch_layout &= ~AV_CH_LAYOUT_STEREO_DOWNMIX;
|
|
|
+
|
|
|
+ /// 2019-5-13添加
|
|
|
+ /// wav/wmv 文件获取到的aCodecCtx->channel_layout为0会导致后面的初始化失败,因此这里需要加个判断。
|
|
|
+ if (in_ch_layout <= 0)
|
|
|
+ {
|
|
|
+ in_ch_layout = av_get_default_channel_layout(aCodecCtx->channels);
|
|
|
+ }
|
|
|
+
|
|
|
+ swrCtx = swr_alloc_set_opts(nullptr, out_ch_layout, out_sample_fmt, out_sample_rate,
|
|
|
+ in_ch_layout, in_sample_fmt, in_sample_rate, 0, nullptr);
|
|
|
+
|
|
|
+ /** Open the resampler with the specified parameters. */
|
|
|
+ int ret = swr_init(swrCtx);
|
|
|
+ if (ret < 0)
|
|
|
+ {
|
|
|
+ char buff[128]={0};
|
|
|
+ av_strerror(ret, buff, 128);
|
|
|
+
|
|
|
+ fprintf(stderr, "Could not open resample context %s\n", buff);
|
|
|
+ swr_free(&swrCtx);
|
|
|
+ swrCtx = nullptr;
|
|
|
+// doOpenVideoFileFailed();
|
|
|
+ goto end;
|
|
|
+ }
|
|
|
+
|
|
|
+ //存储pcm数据
|
|
|
+ int out_linesize = out_sample_rate * audio_tgt_channels;
|
|
|
+
|
|
|
+ // out_linesize = av_samples_get_buffer_size(NULL, audio_tgt_channels, av_get_bytes_per_sample(out_sample_fmt), out_sample_fmt, 1);
|
|
|
+ out_linesize = AVCODEC_MAX_AUDIO_FRAME_SIZE;
|
|
|
+
|
|
|
+
|
|
|
+ mAudioStream = pFormatCtx->streams[audioStream];
|
|
|
+ }
|
|
|
+
|
|
|
}
|
|
|
|
|
|
- while(!feof(fp))
|
|
|
+ av_dump_format(pFormatCtx, 0, file_path, 0); //输出视频信息
|
|
|
+
|
|
|
+// mPlayerState = VideoPlayer_Playing;
|
|
|
+// doPlayerStateChanged(VideoPlayer_Playing, mVideoStream != nullptr, mAudioStream != nullptr);
|
|
|
+
|
|
|
+ mVideoStartTime = av_gettime();
|
|
|
+fprintf(stderr, "%s mIsQuit=%d mIsPause=%d \n", __FUNCTION__, mIsQuit, mIsPause);
|
|
|
+ while (1)
|
|
|
{
|
|
|
- char buf[10240];
|
|
|
- int size = fread(buf, 1, 1024, fp);//从h264文件读1024个字节 (模拟从网络收到h264流)
|
|
|
- int nCount = mAACReader->inputAACData((uint8_t*)buf,size);
|
|
|
+ if (mIsQuit)
|
|
|
+ {
|
|
|
+ //停止播放了
|
|
|
+ break;
|
|
|
+ }
|
|
|
|
|
|
- while(1)
|
|
|
+// if (seek_req)
|
|
|
+// {
|
|
|
+// int stream_index = -1;
|
|
|
+// int64_t seek_target = seek_pos;
|
|
|
+
|
|
|
+// if (videoStream >= 0)
|
|
|
+// stream_index = videoStream;
|
|
|
+// else if (audioStream >= 0)
|
|
|
+// stream_index = audioStream;
|
|
|
+
|
|
|
+// AVRational aVRational = {1, AV_TIME_BASE};
|
|
|
+// if (stream_index >= 0)
|
|
|
+// {
|
|
|
+// seek_target = av_rescale_q(seek_target, aVRational, pFormatCtx->streams[stream_index]->time_base);
|
|
|
+// }
|
|
|
+
|
|
|
+// if (av_seek_frame(pFormatCtx, stream_index, seek_target, AVSEEK_FLAG_BACKWARD) < 0)
|
|
|
+// {
|
|
|
+// fprintf(stderr, "%s: error while seeking\n",pFormatCtx->filename);
|
|
|
+// }
|
|
|
+// else
|
|
|
+// {
|
|
|
+// if (audioStream >= 0)
|
|
|
+// {
|
|
|
+// AVPacket packet;
|
|
|
+// av_new_packet(&packet, 10);
|
|
|
+// strcpy((char*)packet.data,FLUSH_DATA);
|
|
|
+// clearAudioQuene(); //清除队列
|
|
|
+// inputAudioQuene(packet); //往队列中存入用来清除的包
|
|
|
+// }
|
|
|
+
|
|
|
+// if (videoStream >= 0)
|
|
|
+// {
|
|
|
+// AVPacket packet;
|
|
|
+// av_new_packet(&packet, 10);
|
|
|
+// strcpy((char*)packet.data,FLUSH_DATA);
|
|
|
+// clearVideoQuene(); //清除队列
|
|
|
+// inputVideoQuene(packet); //往队列中存入用来清除的包
|
|
|
+// video_clock = 0;
|
|
|
+// }
|
|
|
+
|
|
|
+// mVideoStartTime = av_gettime() - seek_pos;
|
|
|
+// mPauseStartTime = av_gettime();
|
|
|
+// }
|
|
|
+// seek_req = 0;
|
|
|
+// seek_time = seek_pos / 1000000.0;
|
|
|
+// seek_flag_audio = 1;
|
|
|
+// seek_flag_video = 1;
|
|
|
+
|
|
|
+// if (mIsPause)
|
|
|
+// {
|
|
|
+// mIsNeedPause = true;
|
|
|
+// mIsPause = false;
|
|
|
+// }
|
|
|
+
|
|
|
+// }
|
|
|
+
|
|
|
+// //这里做了个限制 当队列里面的数据超过某个大小的时候 就暂停读取 防止一下子就把视频读完了,导致的空间分配不足
|
|
|
+// //这个值可以稍微写大一些
|
|
|
+// if (mAudioPacktList.size() > MAX_AUDIO_SIZE || mVideoPacktList.size() > MAX_VIDEO_SIZE)
|
|
|
+// {
|
|
|
+// mSleep(10);
|
|
|
+// continue;
|
|
|
+// }
|
|
|
+
|
|
|
+// if (mIsPause == true)
|
|
|
+// {
|
|
|
+// mSleep(10);
|
|
|
+// continue;
|
|
|
+// }
|
|
|
+
|
|
|
+ AVPacket packet;
|
|
|
+ if (av_read_frame(pFormatCtx, &packet) < 0)
|
|
|
{
|
|
|
- //从前面读到的数据中获取一个nalu
|
|
|
- AACFramePtr framePtr = mAACReader->getNextFrame();
|
|
|
- if (framePtr == nullptr || framePtr.get() == nullptr) break;
|
|
|
+ mIsReadFinished = true;
|
|
|
|
|
|
- frameNum++;
|
|
|
+ if (mIsQuit)
|
|
|
+ {
|
|
|
+ break; //解码线程也执行完了 可以退出了
|
|
|
+ }
|
|
|
|
|
|
- AACFrame *aacFrame = framePtr.get();
|
|
|
+ MoudleConfig::mSleep(10);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
|
|
|
- PCMFramePtr pcmFramePtr = mAudioDecoder->decode(aacFrame->getBuffer(), aacFrame->getSize());
|
|
|
+ if( packet.stream_index == audioStream )
|
|
|
+ {
|
|
|
+ fprintf(stderr, "%s size=%d pts=%I64d \n", __FUNCTION__, packet.size, packet.pts);
|
|
|
|
|
|
- ///延时等待
|
|
|
- while(1)
|
|
|
+
|
|
|
+ //解码AVPacket->AVFrame
|
|
|
+ if (int ret = avcodec_send_packet(aCodecCtx, &packet) && ret != 0)
|
|
|
{
|
|
|
- if (mAudioPlayer->getPcmFrameSize() <= 3)
|
|
|
- {
|
|
|
- mAudioPlayer->inputPCMFrame(pcmFramePtr);
|
|
|
- break;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- MoudleConfig::mSleep(50);
|
|
|
- }
|
|
|
+ char buffer[1024] = {0};
|
|
|
+ av_strerror(ret, buffer, 1024);
|
|
|
+ fprintf(stderr, "input AVPacket to decoder failed! ret = %d %s\n", ret, buffer);
|
|
|
}
|
|
|
-
|
|
|
- if (mAudioCallBack != nullptr)
|
|
|
+ else
|
|
|
{
|
|
|
- PCMTYPE *buffer = (PCMTYPE *)pcmFramePtr->getBuffer();
|
|
|
-
|
|
|
- ///记录当前帧的所有采样点db值
|
|
|
- std::list<float> leftChannelDbValues;
|
|
|
- std::list<float> righttChannelDbValues;
|
|
|
-
|
|
|
- ///记录当前帧的所有采样点db值总和
|
|
|
- uint64_t leftChannelTotal = 0;
|
|
|
- uint64_t rightChannelTotal = 0;
|
|
|
-
|
|
|
- /// 计算分贝 音频数据与大小
|
|
|
- /// 首先我们分别累加每个采样点的数值,除以采样个数,得到声音平均能量值。
|
|
|
- /// 然后再将其做100与32767之间的等比量化。得到1-100的量化值。
|
|
|
- /// 通常情况下,人声分布在较低的能量范围,这样就会使量化后的数据大致分布在1-20的较小区间,不能够很敏感的感知变化。
|
|
|
- /// 所以我们将其做了5倍的放大,当然计算后大于100的值,我们将其赋值100.
|
|
|
- /// PS:这里的PCM音频数据排列方式为,左右左右左右左右..
|
|
|
- int nums = pcmFramePtr->getSize() / sizeof (PCMTYPE);
|
|
|
- for (int i=0;i<nums;)
|
|
|
+ // while (0 == avcodec_receive_frame(pCodecCtx, pFrame))
|
|
|
+ while(1)
|
|
|
{
|
|
|
- leftChannelTotal += abs(buffer[i]);
|
|
|
- rightChannelTotal += abs(buffer[i+1]);
|
|
|
+ int ret = avcodec_receive_frame(aCodecCtx, aFrame);
|
|
|
+ if (ret != 0)
|
|
|
+ {
|
|
|
+ // char buffer[1024] = {0};
|
|
|
+ // av_strerror(ret, buffer, 1024);
|
|
|
+ // fprintf(stderr, "avcodec_receive_frame = %d %s\n", ret, buffer);
|
|
|
+ break;
|
|
|
+ }
|
|
|
|
|
|
- ///左声道数据放大5倍展示
|
|
|
- leftChannelDbValues.push_back(buffer[i] * 1.0 / MAXPCMVALUE);
|
|
|
+ /// ffmpeg解码之后得到的音频数据不是SDL想要的,
|
|
|
+ /// 因此这里需要重采样成44100 双声道 AV_SAMPLE_FMT_S16
|
|
|
+ if (aFrame_ReSample == NULL)
|
|
|
+ {
|
|
|
+ aFrame_ReSample = av_frame_alloc();
|
|
|
+ }
|
|
|
|
|
|
- if (i % 500 == 0)
|
|
|
+ if (aFrame_ReSample->nb_samples != aFrame->nb_samples)
|
|
|
{
|
|
|
- righttChannelDbValues.push_back(buffer[i+1] * 1.0 / MAXPCMVALUE);
|
|
|
+ aFrame_ReSample->nb_samples = av_rescale_rnd(swr_get_delay(swrCtx, out_sample_rate) + aFrame->nb_samples,
|
|
|
+ out_sample_rate, in_sample_rate, AV_ROUND_UP);
|
|
|
+
|
|
|
+ av_samples_fill_arrays(aFrame_ReSample->data, aFrame_ReSample->linesize, audio_buf, audio_tgt_channels, aFrame_ReSample->nb_samples, out_sample_fmt, 0);
|
|
|
+
|
|
|
}
|
|
|
|
|
|
- i+=2;
|
|
|
- }
|
|
|
+ int len2 = swr_convert(swrCtx, aFrame_ReSample->data, aFrame_ReSample->nb_samples, (const uint8_t**)aFrame->data, aFrame->nb_samples);
|
|
|
+ int resampled_data_size = len2 * audio_tgt_channels * av_get_bytes_per_sample(out_sample_fmt);
|
|
|
|
|
|
- ///记录当前帧的所有采样点db值平均值
|
|
|
- PCMTYPE leftChannels = leftChannelTotal / nums;
|
|
|
- PCMTYPE rightChannels = rightChannelTotal / nums;
|
|
|
+ frameNum++;
|
|
|
+ fprintf(stderr, "%s [%d] size=%d pts=%I64d %d\n", __FUNCTION__, frameNum, packet.size, packet.pts, resampled_data_size);
|
|
|
|
|
|
- float leftChannelDb = leftChannels * 5.0 / MAXPCMVALUE;
|
|
|
- if (leftChannelDb > 1.0f)
|
|
|
- {
|
|
|
- leftChannelDb = 1.0f;
|
|
|
- }
|
|
|
+ PCMFramePtr pcmFramePtr = std::make_shared<PCMFrame>();
|
|
|
+ pcmFramePtr->setFrameBuffer(audio_buf, resampled_data_size);
|
|
|
|
|
|
- float rightChannelDb = rightChannels * 5.0 / MAXPCMVALUE;
|
|
|
- if (rightChannelDb > 1.0f)
|
|
|
- {
|
|
|
- rightChannelDb = 1.0f;
|
|
|
+ mAudioPlayer->inputPCMFrame(pcmFramePtr);
|
|
|
+
|
|
|
+ static FILE * fp = fopen("out.pcm", "wb");
|
|
|
+ fwrite(audio_buf, 1, resampled_data_size, fp);
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- float progress = frameNum * 1.0 / totalFrameNum;
|
|
|
- currentTime = frameNum * 1024.0 / 44100 * 1000; //单位是毫秒
|
|
|
+ //保存重采样之前的一个声道的数据方法
|
|
|
+ //size_t unpadded_linesize = aFrame->nb_samples * av_get_bytes_per_sample((AVSampleFormat) aFrame->format);
|
|
|
+ //static FILE * fp = fopen("out.pcm", "wb");
|
|
|
+ //fwrite(aFrame->extended_data[0], 1, unpadded_linesize, fp);
|
|
|
|
|
|
- mAudioCallBack->onGetPcmFrame(pcmFramePtr);
|
|
|
- mAudioCallBack->onUpdatePlayingTime(totalTime, currentTime);
|
|
|
- mAudioCallBack->onUpdatePlayingValue(leftChannelDb, rightChannelDb, leftChannelDbValues, righttChannelDbValues, progress);
|
|
|
- }
|
|
|
+ av_packet_unref(&packet);
|
|
|
}
|
|
|
+ else
|
|
|
+ {
|
|
|
+ // Free the packet that was allocated by av_read_frame
|
|
|
+ av_packet_unref(&packet);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ ///文件读取结束 跳出循环的情况
|
|
|
+ ///等待播放完毕
|
|
|
+ while (!mIsQuit)
|
|
|
+ {
|
|
|
+ MoudleConfig::mSleep(100);
|
|
|
+ }
|
|
|
+
|
|
|
+end:
|
|
|
+
|
|
|
+// clearAudioQuene();
|
|
|
+// clearVideoQuene();
|
|
|
+
|
|
|
+// if (mPlayerState != VideoPlayer_Stop) //不是外部调用的stop 是正常播放结束
|
|
|
+// {
|
|
|
+// stop();
|
|
|
+// }
|
|
|
+
|
|
|
+// while((mVideoStream != nullptr && !mIsVideoThreadFinished) || (mAudioStream != nullptr && !mIsAudioThreadFinished))
|
|
|
+// {
|
|
|
+// mSleep(10);
|
|
|
+// } //确保视频线程结束后 再销毁队列
|
|
|
+
|
|
|
+ if (swrCtx != nullptr)
|
|
|
+ {
|
|
|
+ swr_free(&swrCtx);
|
|
|
+ swrCtx = nullptr;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (aFrame != nullptr)
|
|
|
+ {
|
|
|
+ av_frame_free(&aFrame);
|
|
|
+ aFrame = nullptr;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (aFrame_ReSample != nullptr)
|
|
|
+ {
|
|
|
+ av_frame_free(&aFrame_ReSample);
|
|
|
+ aFrame_ReSample = nullptr;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (aCodecCtx != nullptr)
|
|
|
+ {
|
|
|
+ avcodec_close(aCodecCtx);
|
|
|
+ aCodecCtx = nullptr;
|
|
|
}
|
|
|
|
|
|
- mAudioDecoder->closeDecoder();
|
|
|
+ if (pCodecCtx != nullptr)
|
|
|
+ {
|
|
|
+ avcodec_close(pCodecCtx);
|
|
|
+ pCodecCtx = nullptr;
|
|
|
+ }
|
|
|
+
|
|
|
+ avformat_close_input(&pFormatCtx);
|
|
|
+ avformat_free_context(pFormatCtx);
|
|
|
+
|
|
|
+// doPlayerStateChanged(VideoPlayer_Stop, mVideoStream != nullptr, mAudioStream != nullptr);
|
|
|
+
|
|
|
+ mIsReadThreadFinished = true;
|
|
|
+
|
|
|
+fprintf(stderr, "%s finished \n", __FUNCTION__);
|
|
|
}
|
|
|
+
|
|
|
+//void ReadAudioFileThread::run()
|
|
|
+//{
|
|
|
+
|
|
|
+// char *fileName = mFileName;
|
|
|
+// FILE *fp = fopen(fileName, "rb");
|
|
|
+// if (fp == nullptr)
|
|
|
+// {
|
|
|
+// fprintf(stderr, "AAC file not exist! \n");
|
|
|
+// return;
|
|
|
+// }
|
|
|
+
|
|
|
+// mAudioPlayer->startPlay();
|
|
|
+
|
|
|
+// int totalFrameNum = 0; //总帧数
|
|
|
+// int frameNum = 0; //当前播放的帧序号
|
|
|
+// uint32_t totalTime = 0; //总时长(毫秒)
|
|
|
+// uint32_t currentTime = 0; //当前播放时间(毫秒)
|
|
|
+
|
|
|
+// ///获取音频强度数据,用于绘制波形图
|
|
|
+// {
|
|
|
+// std::list<float> mLeftChannelDbValues;
|
|
|
+// std::list<float> mRighttChannelDbValues;
|
|
|
+
|
|
|
+// while(!feof(fp))
|
|
|
+// {
|
|
|
+//// char buf[10240];
|
|
|
+//// int size = fread(buf, 1, 1024, fp);//从h264文件读1024个字节 (模拟从网络收到h264流)
|
|
|
+//// int nCount = mAACReader->inputAACData((uint8_t*)buf,size);
|
|
|
+
|
|
|
+//// while(1)
|
|
|
+//// {
|
|
|
+//// //从前面读到的数据中获取一个nalu
|
|
|
+//// AACFramePtr framePtr = mAACReader->getNextFrame();
|
|
|
+//// if (framePtr == nullptr || framePtr.get() == nullptr) break;
|
|
|
+
|
|
|
+//// AACFrame *aacFrame = framePtr.get();
|
|
|
+
|
|
|
+//// PCMFramePtr pcmFramePtr = mAudioDecoder->decode(aacFrame->getBuffer(), aacFrame->getSize());
|
|
|
+
|
|
|
+//// PCMTYPE *buffer = (PCMTYPE *)pcmFramePtr->getBuffer();
|
|
|
+
|
|
|
+//// /// 这里直接使用前两个字节转成short,然后作为纵坐标来绘制波形图。
|
|
|
+//// /// PS:这里的PCM音频数据排列方式为,左右左右左右左右...
|
|
|
+//// mLeftChannelDbValues.push_back(buffer[0] * 1.0 / MAXPCMVALUE);
|
|
|
+//// mRighttChannelDbValues.push_back(buffer[1] * 1.0 / MAXPCMVALUE);
|
|
|
+
|
|
|
+//// totalFrameNum++;
|
|
|
+//// }
|
|
|
+// }
|
|
|
+
|
|
|
+// if (mAudioCallBack != nullptr)
|
|
|
+// {
|
|
|
+// mAudioCallBack->onGetPcmWaveValues(mLeftChannelDbValues, mRighttChannelDbValues);
|
|
|
+// }
|
|
|
+
|
|
|
+// fseek(fp, 0, SEEK_SET);
|
|
|
+// }
|
|
|
+
|
|
|
+// ///计算总时长
|
|
|
+// {
|
|
|
+// /// 这里一帧音频的采样是1024,音频的采样率是一秒钟44100次,总时长便很容易就算。
|
|
|
+// /// 当然也可以通过直接计算数据总大小,原理都是类似。
|
|
|
+// totalTime = totalFrameNum * 1024.0 / 44100 * 1000; //单位是毫秒
|
|
|
+// }
|
|
|
+
|
|
|
+// while(!feof(fp))
|
|
|
+// {
|
|
|
+//// char buf[10240];
|
|
|
+//// int size = fread(buf, 1, 1024, fp);//从h264文件读1024个字节 (模拟从网络收到h264流)
|
|
|
+//// int nCount = mAACReader->inputAACData((uint8_t*)buf,size);
|
|
|
+
|
|
|
+//// while(1)
|
|
|
+//// {
|
|
|
+//// //从前面读到的数据中获取一个nalu
|
|
|
+//// AACFramePtr framePtr = mAACReader->getNextFrame();
|
|
|
+//// if (framePtr == nullptr || framePtr.get() == nullptr) break;
|
|
|
+
|
|
|
+//// frameNum++;
|
|
|
+
|
|
|
+//// AACFrame *aacFrame = framePtr.get();
|
|
|
+
|
|
|
+//// PCMFramePtr pcmFramePtr = mAudioDecoder->decode(aacFrame->getBuffer(), aacFrame->getSize());
|
|
|
+
|
|
|
+//// ///延时等待
|
|
|
+//// while(1)
|
|
|
+//// {
|
|
|
+//// if (mAudioPlayer->getPcmFrameSize() <= 3)
|
|
|
+//// {
|
|
|
+//// mAudioPlayer->inputPCMFrame(pcmFramePtr);
|
|
|
+//// break;
|
|
|
+//// }
|
|
|
+//// else
|
|
|
+//// {
|
|
|
+//// MoudleConfig::mSleep(50);
|
|
|
+//// }
|
|
|
+//// }
|
|
|
+
|
|
|
+//// if (mAudioCallBack != nullptr)
|
|
|
+//// {
|
|
|
+//// PCMTYPE *buffer = (PCMTYPE *)pcmFramePtr->getBuffer();
|
|
|
+
|
|
|
+//// ///记录当前帧的所有采样点db值
|
|
|
+//// std::list<float> leftChannelDbValues;
|
|
|
+//// std::list<float> righttChannelDbValues;
|
|
|
+
|
|
|
+//// ///记录当前帧的所有采样点db值总和
|
|
|
+//// uint64_t leftChannelTotal = 0;
|
|
|
+//// uint64_t rightChannelTotal = 0;
|
|
|
+
|
|
|
+//// /// 计算分贝 音频数据与大小
|
|
|
+//// /// 首先我们分别累加每个采样点的数值,除以采样个数,得到声音平均能量值。
|
|
|
+//// /// 然后再将其做100与32767之间的等比量化。得到1-100的量化值。
|
|
|
+//// /// 通常情况下,人声分布在较低的能量范围,这样就会使量化后的数据大致分布在1-20的较小区间,不能够很敏感的感知变化。
|
|
|
+//// /// 所以我们将其做了5倍的放大,当然计算后大于100的值,我们将其赋值100.
|
|
|
+//// /// PS:这里的PCM音频数据排列方式为,左右左右左右左右..
|
|
|
+//// int nums = pcmFramePtr->getSize() / sizeof (PCMTYPE);
|
|
|
+//// for (int i=0;i<nums;)
|
|
|
+//// {
|
|
|
+//// leftChannelTotal += abs(buffer[i]);
|
|
|
+//// rightChannelTotal += abs(buffer[i+1]);
|
|
|
+
|
|
|
+//// ///左声道数据放大5倍展示
|
|
|
+//// leftChannelDbValues.push_back(buffer[i] * 1.0 / MAXPCMVALUE);
|
|
|
+
|
|
|
+//// if (i % 500 == 0)
|
|
|
+//// {
|
|
|
+//// righttChannelDbValues.push_back(buffer[i+1] * 1.0 / MAXPCMVALUE);
|
|
|
+//// }
|
|
|
+
|
|
|
+//// i+=2;
|
|
|
+//// }
|
|
|
+
|
|
|
+//// ///记录当前帧的所有采样点db值平均值
|
|
|
+//// PCMTYPE leftChannels = leftChannelTotal / nums;
|
|
|
+//// PCMTYPE rightChannels = rightChannelTotal / nums;
|
|
|
+
|
|
|
+//// float leftChannelDb = leftChannels * 5.0 / MAXPCMVALUE;
|
|
|
+//// if (leftChannelDb > 1.0f)
|
|
|
+//// {
|
|
|
+//// leftChannelDb = 1.0f;
|
|
|
+//// }
|
|
|
+
|
|
|
+//// float rightChannelDb = rightChannels * 5.0 / MAXPCMVALUE;
|
|
|
+//// if (rightChannelDb > 1.0f)
|
|
|
+//// {
|
|
|
+//// rightChannelDb = 1.0f;
|
|
|
+//// }
|
|
|
+
|
|
|
+//// float progress = frameNum * 1.0 / totalFrameNum;
|
|
|
+//// currentTime = frameNum * 1024.0 / 44100 * 1000; //单位是毫秒
|
|
|
+
|
|
|
+//// mAudioCallBack->onGetPcmFrame(pcmFramePtr);
|
|
|
+//// mAudioCallBack->onUpdatePlayingTime(totalTime, currentTime);
|
|
|
+//// mAudioCallBack->onUpdatePlayingValue(leftChannelDb, rightChannelDb, leftChannelDbValues, righttChannelDbValues, progress);
|
|
|
+//// }
|
|
|
+//// }
|
|
|
+// }
|
|
|
+
|
|
|
+//}
|