|
|
@@ -55,6 +55,7 @@ static int audio_decode_frame(AVCodecContext *p_codec_ctx, packet_queue_t *p_pkt
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ //printf("avcodec_receive_frame ret = %d, begin packet_queue_get\n", ret);
|
|
|
// 1. 取出一个packet。使用pkt对应的serial赋值给d->pkt_serial
|
|
|
if (packet_queue_get(p_pkt_queue, &pkt, true) < 0)
|
|
|
{
|
|
|
@@ -63,10 +64,12 @@ static int audio_decode_frame(AVCodecContext *p_codec_ctx, packet_queue_t *p_pkt
|
|
|
}
|
|
|
|
|
|
// packet_queue中第一个总是flush_pkt。每次seek操作会插入flush_pkt,更新serial,开启新的播放序列
|
|
|
- if (pkt.data == NULL)
|
|
|
+ //hostapi->Debug("packet_queue_get pkt.data == 0x%0x, pkt.size == %d.", pkt.data, pkt.size);
|
|
|
+ if (NULL == pkt.data || 0 == pkt.size)
|
|
|
{
|
|
|
// 复位解码器内部状态/刷新内部缓冲区。当seek操作或切换流时应调用此函数。
|
|
|
avcodec_flush_buffers(p_codec_ctx);
|
|
|
+ return -2;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
@@ -76,7 +79,6 @@ static int audio_decode_frame(AVCodecContext *p_codec_ctx, packet_queue_t *p_pkt
|
|
|
int iresult = avcodec_send_packet(p_codec_ctx, &pkt);
|
|
|
if (AVERROR(EAGAIN) == iresult)
|
|
|
{
|
|
|
- //av_log(NULL, AV_LOG_ERROR, "receive_frame and send_packet both returned EAGAIN, which is an API violation.\n");
|
|
|
hostapi->Debug("receive_frame and send_packet both returned EAGAIN, which is an API violation.");
|
|
|
}
|
|
|
if (0 == iresult)
|
|
|
@@ -99,6 +101,7 @@ static int audio_decode_thread(void *arg)
|
|
|
int got_frame = 0;
|
|
|
AVRational tb;
|
|
|
int ret = 0;
|
|
|
+ int inullpacket = 0;
|
|
|
|
|
|
if (p_frame == NULL){
|
|
|
return AVERROR(ENOMEM);
|
|
|
@@ -109,9 +112,19 @@ static int audio_decode_thread(void *arg)
|
|
|
//printf("%s:%d is->index = %d, is->p_acodec_ctx[is->index] = 0x%0x\n", __FUNCTION__, __LINE__, is->index, is->p_acodec_ctx[is->index]);
|
|
|
got_frame = audio_decode_frame(is->p_acodec_ctx[is->index], &is->audio_pkt_queue, p_frame, is->rvc_hostapi);
|
|
|
if (got_frame < 0){
|
|
|
- is->rvc_hostapi->Debug("audio_decode_frame < 0, goto end");
|
|
|
- goto the_end;
|
|
|
- }
|
|
|
+ if(-2 == got_frame && inullpacket < 2){
|
|
|
+ inullpacket++;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ is->rvc_hostapi->Debug(" audio_decode_frame < 0, goto end");
|
|
|
+ goto the_end;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ inullpacket = 0;
|
|
|
+ }
|
|
|
|
|
|
if (got_frame)
|
|
|
{
|
|
|
@@ -138,9 +151,11 @@ static int audio_decode_thread(void *arg)
|
|
|
the_end:
|
|
|
|
|
|
av_frame_free(&p_frame);
|
|
|
+ SDL_Delay(1000);
|
|
|
+ is->abort_request = 1;
|
|
|
is->rvc_hostapi->Debug("audio decode thread exit, thread id is %lu, and is->abort_request = %d", SDL_ThreadID(), is->abort_request);
|
|
|
-
|
|
|
- return ret;
|
|
|
+
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
int open_audio_stream(player_stat_t *is)
|
|
|
@@ -202,11 +217,11 @@ int open_audio_stream(player_stat_t *is)
|
|
|
|
|
|
static int audio_resample(player_stat_t *is, int64_t audio_callback_time)
|
|
|
{
|
|
|
- int data_size, resampled_data_size;
|
|
|
- int64_t dec_channel_layout;
|
|
|
- av_unused double audio_clock0;
|
|
|
- int wanted_nb_samples;
|
|
|
- frame_t *af;
|
|
|
+ int data_size = 0, resampled_data_size = 0;
|
|
|
+ int64_t dec_channel_layout = 0;
|
|
|
+ av_unused double audio_clock0 = 0.0;
|
|
|
+ int wanted_nb_samples = 0;
|
|
|
+ frame_t *af = NULL;
|
|
|
|
|
|
#if defined(_WIN32)
|
|
|
while (frame_queue_nb_remaining(&is->audio_frm_queue) == 0)
|
|
|
@@ -219,14 +234,15 @@ static int audio_resample(player_stat_t *is, int64_t audio_callback_time)
|
|
|
|
|
|
// 若队列头部可读,则由af指向可读帧
|
|
|
if (!(af = frame_queue_peek_readable(&is->audio_frm_queue))) {
|
|
|
- return -1;
|
|
|
+ is->rvc_hostapi->Debug("%s:%d abort_request flag is true, function return", __FUNCTION__, __LINE__);
|
|
|
+ return -2;
|
|
|
}
|
|
|
frame_queue_next(&is->audio_frm_queue);
|
|
|
|
|
|
// 根据frame中指定的音频参数获取缓冲区的大小
|
|
|
- data_size = av_samples_get_buffer_size(NULL, af->frame->channels, // 本行两参数:linesize,声道数
|
|
|
- af->frame->nb_samples, // 本行一参数:本帧中包含的单个声道中的样本数
|
|
|
- (AVSampleFormat)af->frame->format, 1); // 本行两参数:采样格式,不对齐
|
|
|
+ data_size = av_samples_get_buffer_size(NULL, af->frame->channels, // 本行两参数:linesize,声道数
|
|
|
+ af->frame->nb_samples, // 本行一参数:本帧中包含的单个声道中的样本数
|
|
|
+ (AVSampleFormat)af->frame->format, 1); // 本行两参数:采样格式,不对齐
|
|
|
|
|
|
// 获取声道布局
|
|
|
dec_channel_layout =
|
|
|
@@ -275,28 +291,24 @@ static int audio_resample(player_stat_t *is, int64_t audio_callback_time)
|
|
|
int out_count = (int64_t)wanted_nb_samples * is->audio_param_tgt.freq / af->frame->sample_rate + 256;
|
|
|
// 重采样输出参数:输出音频缓冲区尺寸(以字节为单位)
|
|
|
int out_size = av_samples_get_buffer_size(NULL, is->audio_param_tgt.channels, out_count, is->audio_param_tgt.fmt, 0);
|
|
|
- int len2;
|
|
|
- if (out_size < 0)
|
|
|
- {
|
|
|
- //av_log(NULL, AV_LOG_ERROR, "av_samples_get_buffer_size() failed\n");
|
|
|
- //is->rvc_log("av_samples_get_buffer_size() failed.");
|
|
|
+ int len2 = 0;
|
|
|
+ if (out_size < 0){
|
|
|
+ is->rvc_hostapi->Debug("av_samples_get_buffer_size() failed.");
|
|
|
return -1;
|
|
|
}
|
|
|
av_fast_malloc(&is->audio_frm_rwr, &is->audio_frm_rwr_size, out_size);
|
|
|
- if (!is->audio_frm_rwr)
|
|
|
- return AVERROR(ENOMEM);
|
|
|
+ if (!is->audio_frm_rwr) {
|
|
|
+ return AVERROR(ENOMEM);
|
|
|
+ }
|
|
|
// 音频重采样:返回值是重采样后得到的音频数据中单个声道的样本数
|
|
|
len2 = swr_convert(is->audio_swr_ctx, out, out_count, in, af->frame->nb_samples);
|
|
|
- if (len2 < 0)
|
|
|
- {
|
|
|
- //av_log(NULL, AV_LOG_ERROR, "swr_convert() failed\n");
|
|
|
- //is->rvc_log("swr_convert() failed.");
|
|
|
+ if (len2 < 0){
|
|
|
+ is->rvc_hostapi->Debug("swr_convert() failed.");
|
|
|
return -1;
|
|
|
}
|
|
|
- if (len2 == out_count)
|
|
|
- {
|
|
|
- //av_log(NULL, AV_LOG_WARNING, "audio buffer is probably too small\n");
|
|
|
- //is->rvc_log("audio buffer is probably too small.");
|
|
|
+
|
|
|
+ if (len2 == out_count){
|
|
|
+ is->rvc_hostapi->Debug("audio buffer is probably too small.");
|
|
|
if (swr_init(is->audio_swr_ctx) < 0)
|
|
|
swr_free(&is->audio_swr_ctx);
|
|
|
}
|
|
|
@@ -313,12 +325,10 @@ static int audio_resample(player_stat_t *is, int64_t audio_callback_time)
|
|
|
|
|
|
audio_clock0 = is->audio_clock;
|
|
|
/* update the audio clock with the pts */
|
|
|
- if (!isnan(af->pts))
|
|
|
- {
|
|
|
+ if (!isnan(af->pts)){
|
|
|
is->audio_clock = af->pts + (double)af->frame->nb_samples / af->frame->sample_rate;
|
|
|
}
|
|
|
- else
|
|
|
- {
|
|
|
+ else{
|
|
|
is->audio_clock = NAN;
|
|
|
}
|
|
|
is->audio_clock_serial = af->serial;
|
|
|
@@ -340,8 +350,8 @@ static int audio_resample(player_stat_t *is, int64_t audio_callback_time)
|
|
|
static int open_audio_playing(void *arg)
|
|
|
{
|
|
|
player_stat_t *is = (player_stat_t *)arg;
|
|
|
- SDL_AudioSpec wanted_spec;
|
|
|
- SDL_AudioSpec actual_spec;
|
|
|
+ SDL_AudioSpec wanted_spec = {0};
|
|
|
+ SDL_AudioSpec actual_spec = {0};
|
|
|
|
|
|
// 2. 打开音频设备并创建音频处理线程
|
|
|
// 2.1 打开音频设备,获取SDL设备支持的音频参数actual_spec(期望的参数是wanted_spec,实际得到actual_spec)
|
|
|
@@ -358,10 +368,14 @@ static int open_audio_playing(void *arg)
|
|
|
wanted_spec.samples = FFMAX(SDL_AUDIO_MIN_BUFFER_SIZE, 2 << av_log2(wanted_spec.freq / SDL_AUDIO_MAX_CALLBACKS_PER_SEC));
|
|
|
wanted_spec.callback = sdl_audio_callback; // 回调函数,若为NULL,则应使用SDL_QueueAudio()机制
|
|
|
wanted_spec.userdata = is; // 提供给回调函数的参数
|
|
|
- if (SDL_OpenAudio(&wanted_spec, &actual_spec) < 0)
|
|
|
- {
|
|
|
- is->rvc_hostapi->Debug("SDL_OpenAudio() failed: %s.", SDL_GetError());
|
|
|
- return -1;
|
|
|
+ if (SDL_OpenAudio(&wanted_spec, &actual_spec) < 0){
|
|
|
+ is->rvc_hostapi->Debug("SDL_OpenAudio() failed: %s,try close and retry", SDL_GetError());
|
|
|
+ SDL_CloseAudio();
|
|
|
+ if (SDL_OpenAudio(&wanted_spec, &actual_spec) < 0) {
|
|
|
+ is->rvc_hostapi->Debug("SDL_OpenAudio() failed: %s.", SDL_GetError());
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
}
|
|
|
|
|
|
// 2.2 根据SDL音频参数构建音频重采样参数
|
|
|
@@ -376,9 +390,7 @@ static int open_audio_playing(void *arg)
|
|
|
is->audio_param_tgt.channels = actual_spec.channels;
|
|
|
is->audio_param_tgt.frame_size = av_samples_get_buffer_size(NULL, actual_spec.channels, 1, is->audio_param_tgt.fmt, 1);
|
|
|
is->audio_param_tgt.bytes_per_sec = av_samples_get_buffer_size(NULL, actual_spec.channels, actual_spec.freq, is->audio_param_tgt.fmt, 1);
|
|
|
- if (is->audio_param_tgt.bytes_per_sec <= 0 || is->audio_param_tgt.frame_size <= 0)
|
|
|
- {
|
|
|
- //av_log(NULL, AV_LOG_ERROR, "av_samples_get_buffer_size failed\n");
|
|
|
+ if (is->audio_param_tgt.bytes_per_sec <= 0 || is->audio_param_tgt.frame_size <= 0){
|
|
|
is->rvc_hostapi->Debug("av_samples_get_buffer_size failed.");
|
|
|
return -1;
|
|
|
}
|
|
|
@@ -393,21 +405,30 @@ static int open_audio_playing(void *arg)
|
|
|
// 在暂停期间,会将静音值往音频设备写。
|
|
|
SDL_PauseAudio(0);
|
|
|
|
|
|
- SDL_Event event;
|
|
|
- while (true)
|
|
|
- {
|
|
|
- SDL_PumpEvents();
|
|
|
- while (!SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT))
|
|
|
- {
|
|
|
- SDL_Delay(100);
|
|
|
- SDL_PumpEvents();
|
|
|
- }
|
|
|
- is->rvc_hostapi->Debug("open_audio_playing event.type = 0x%0x.", event.type);
|
|
|
- if (FF_QUIT_EVENT == event.type) {
|
|
|
- SDL_Delay(2000);
|
|
|
- return 0;
|
|
|
- }
|
|
|
+
|
|
|
+ while (is->abort_request == 0){
|
|
|
+ SDL_Delay(100);
|
|
|
}
|
|
|
+
|
|
|
+ SDL_CloseAudio();
|
|
|
+
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ //SDL_Event event;
|
|
|
+ //while (true)
|
|
|
+ //{
|
|
|
+ // SDL_PumpEvents();
|
|
|
+ // while (!SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT))
|
|
|
+ // {
|
|
|
+ // SDL_Delay(100);
|
|
|
+ // SDL_PumpEvents();
|
|
|
+ // }
|
|
|
+ // is->rvc_hostapi->Debug("open_audio_playing event.type = 0x%0x.", event.type);
|
|
|
+ // if (FF_QUIT_EVENT == event.type) {
|
|
|
+ // SDL_Delay(2000);
|
|
|
+ // return 0;
|
|
|
+ // }
|
|
|
+ //}
|
|
|
}
|
|
|
|
|
|
// 音频处理回调函数。读队列获取音频包,解码,播放
|
|
|
@@ -420,25 +441,25 @@ static int open_audio_playing(void *arg)
|
|
|
static void sdl_audio_callback(void *opaque, Uint8 *stream, int len)
|
|
|
{
|
|
|
player_stat_t *is = (player_stat_t *)opaque;
|
|
|
- int audio_size, len1;
|
|
|
+ int audio_size = 0, len1 = 0;
|
|
|
|
|
|
int64_t audio_callback_time = av_gettime_relative();
|
|
|
- //is->rvc_hostapi->Debug("sdl_audio_callback audo len is %d.", len);
|
|
|
+ //is->rvc_hostapi->Debug("sdl_audio_callback audo len is %d. and audio_frm_size is %d.", len, (int)is->audio_frm_size);
|
|
|
while (len > 0 && 0 == is->abort_request) // 输入参数len等于is->audio_hw_buf_size,是audio_open()中申请到的SDL音频缓冲区大小
|
|
|
{
|
|
|
- if (is->audio_cp_index >= (int)is->audio_frm_size)
|
|
|
- {
|
|
|
+ if (is->audio_cp_index >= (int)is->audio_frm_size){
|
|
|
// 1. 从音频frame队列中取出一个frame,转换为音频设备支持的格式,返回值是重采样音频帧的大小
|
|
|
audio_size = audio_resample(is, audio_callback_time);
|
|
|
//is->rvc_hostapi->Debug("audio_resample audio_size is %d.", audio_size);
|
|
|
- if (audio_size < 0)
|
|
|
- {
|
|
|
+ if (audio_size < 0){
|
|
|
+ if (-2 == audio_size) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
/* if error, just output silence */
|
|
|
is->p_audio_frm = NULL;
|
|
|
is->audio_frm_size = SDL_AUDIO_MIN_BUFFER_SIZE / is->audio_param_tgt.frame_size * is->audio_param_tgt.frame_size;
|
|
|
}
|
|
|
- else
|
|
|
- {
|
|
|
+ else{
|
|
|
is->audio_frm_size = audio_size;
|
|
|
}
|
|
|
is->audio_cp_index = 0;
|
|
|
@@ -446,21 +467,16 @@ static void sdl_audio_callback(void *opaque, Uint8 *stream, int len)
|
|
|
// 引入is->audio_cp_index的作用:防止一帧音频数据大小超过SDL音频缓冲区大小,这样一帧数据需要经过多次拷贝
|
|
|
// 用is->audio_cp_index标识重采样帧中已拷入SDL音频缓冲区的数据位置索引,len1表示本次拷贝的数据量
|
|
|
len1 = is->audio_frm_size - is->audio_cp_index;
|
|
|
- if (len1 > len)
|
|
|
- {
|
|
|
+ if (len1 > len){
|
|
|
len1 = len;
|
|
|
}
|
|
|
//printf("len1 = %d\n", len1);
|
|
|
// 2. 将转换后的音频数据拷贝到音频缓冲区stream中,之后的播放就是音频设备驱动程序的工作了
|
|
|
- if (is->p_audio_frm != NULL)
|
|
|
- {
|
|
|
- //memcpy(stream, (uint8_t *)is->p_audio_frm + is->audio_cp_index, len1);
|
|
|
+ if (is->p_audio_frm != NULL){
|
|
|
SDL_memset(stream, 0, len1);
|
|
|
SDL_MixAudio(stream, (uint8_t*)is->p_audio_frm + is->audio_cp_index, len1, is->uVolume);
|
|
|
}
|
|
|
- else
|
|
|
- {
|
|
|
- //memset(stream, 0, len1);
|
|
|
+ else{
|
|
|
SDL_memset(stream, 0, len1);
|
|
|
}
|
|
|
|
|
|
@@ -470,7 +486,7 @@ static void sdl_audio_callback(void *opaque, Uint8 *stream, int len)
|
|
|
}
|
|
|
// is->audio_write_buf_size是本帧中尚未拷入SDL音频缓冲区的数据量
|
|
|
is->audio_write_buf_size = is->audio_frm_size - is->audio_cp_index;
|
|
|
- //is->rvc_log("audio_write_buf_size == %d.", is->audio_write_buf_size);
|
|
|
+ //is->rvc_hostapi->Debug("audio_write_buf_size == %d.", is->audio_write_buf_size);
|
|
|
/* Let's assume the audio driver that is used by SDL has two periods. */
|
|
|
// 3. 更新时钟
|
|
|
if (!isnan(is->audio_clock))
|