static void audio_process_audio(audio_decoder_t *ad, media_buf_t *mb) { const audio_class_t *ac = ad->ad_ac; AVFrame *frame = ad->ad_frame; media_pipe_t *mp = ad->ad_mp; media_queue_t *mq = &mp->mp_audio; int r; int got_frame; if(mb->mb_skip || mb->mb_stream != mq->mq_stream) return; while(mb->mb_size) { if(mb->mb_cw == NULL) { frame->sample_rate = mb->mb_rate; frame->format = AV_SAMPLE_FMT_S16; switch(mb->mb_channels) { case 1: frame->channel_layout = AV_CH_LAYOUT_MONO; frame->nb_samples = mb->mb_size / 2; break; case 2: frame->channel_layout = AV_CH_LAYOUT_STEREO; frame->nb_samples = mb->mb_size / 4; break; default: abort(); } frame->data[0] = mb->mb_data; frame->linesize[0] = 0; r = mb->mb_size; got_frame = 1; } else { media_codec_t *mc = mb->mb_cw; AVCodecContext *ctx = mc->ctx; if(mc->codec_id != ad->ad_in_codec_id) { AVCodec *codec = avcodec_find_decoder(mc->codec_id); TRACE(TRACE_DEBUG, "audio", "Codec changed to %s (0x%x)", codec ? codec->name : "???", mc->codec_id); ad->ad_in_codec_id = mc->codec_id; ad->ad_in_sample_rate = 0; audio_cleanup_spdif_muxer(ad); ad->ad_mode = ac->ac_get_mode != NULL ? ac->ac_get_mode(ad, mc->codec_id, ctx ? ctx->extradata : NULL, ctx ? ctx->extradata_size : 0) : AUDIO_MODE_PCM; if(ad->ad_mode == AUDIO_MODE_SPDIF) { audio_setup_spdif_muxer(ad, codec, mq); } else if(ad->ad_mode == AUDIO_MODE_CODED) { hts_mutex_lock(&mp->mp_mutex); ac->ac_deliver_coded_locked(ad, mb->mb_data, mb->mb_size, mb->mb_pts, mb->mb_epoch); hts_mutex_unlock(&mp->mp_mutex); return; } } if(ad->ad_spdif_muxer != NULL) { mb->mb_pkt.stream_index = 0; ad->ad_pts = mb->mb_pts; ad->ad_epoch = mb->mb_epoch; mb->mb_pts = AV_NOPTS_VALUE; mb->mb_dts = AV_NOPTS_VALUE; av_write_frame(ad->ad_spdif_muxer, &mb->mb_pkt); avio_flush(ad->ad_spdif_muxer->pb); return; } if(ad->ad_mode == AUDIO_MODE_CODED) { ad->ad_pts = mb->mb_pts; ad->ad_epoch = mb->mb_epoch; } if(ctx == NULL) { AVCodec *codec = avcodec_find_decoder(mc->codec_id); assert(codec != NULL); // Checked in libav.c ctx = mc->ctx = avcodec_alloc_context3(codec); if(ad->ad_stereo_downmix) ctx->request_channel_layout = AV_CH_LAYOUT_STEREO; if(avcodec_open2(mc->ctx, codec, NULL) < 0) { av_freep(&mc->ctx); return; } } r = avcodec_decode_audio4(ctx, frame, &got_frame, &mb->mb_pkt); if(r < 0) return; if(frame->sample_rate == 0) { frame->sample_rate = ctx->sample_rate; if(frame->sample_rate == 0 && mb->mb_cw->fmt_ctx) frame->sample_rate = mb->mb_cw->fmt_ctx->sample_rate; if(frame->sample_rate == 0) { if(!ad->ad_sample_rate_fail) { ad->ad_sample_rate_fail = 1; TRACE(TRACE_ERROR, "Audio", "Unable to determine sample rate"); } return; } } if(frame->channel_layout == 0) { frame->channel_layout = av_get_default_channel_layout(ctx->channels); if(frame->channel_layout == 0) { if(!ad->ad_channel_layout_fail) { ad->ad_channel_layout_fail = 1; TRACE(TRACE_ERROR, "Audio", "Unable to map %d channels to channel layout"); } return; } } if(mp->mp_stats) mp_set_mq_meta(mq, ctx->codec, ctx); } if(mb->mb_pts != PTS_UNSET) { int od = 0, id = 0; if(ad->ad_avr != NULL) { od = avresample_available(ad->ad_avr) * 1000000LL / ad->ad_out_sample_rate; id = avresample_get_delay(ad->ad_avr) * 1000000LL / frame->sample_rate; } ad->ad_pts = mb->mb_pts - od - id; ad->ad_epoch = mb->mb_epoch; if(mb->mb_drive_clock) mp_set_current_time(mp, mb->mb_pts - ad->ad_delay, mb->mb_epoch, mb->mb_delta); mb->mb_pts = PTS_UNSET; // No longer valid } mb->mb_data += r; mb->mb_size -= r; if(got_frame) { if(frame->sample_rate != ad->ad_in_sample_rate || frame->format != ad->ad_in_sample_format || frame->channel_layout != ad->ad_in_channel_layout || ad->ad_want_reconfig) { ad->ad_want_reconfig = 0; ad->ad_in_sample_rate = frame->sample_rate; ad->ad_in_sample_format = frame->format; ad->ad_in_channel_layout = frame->channel_layout; ac->ac_reconfig(ad); if(ad->ad_avr == NULL) ad->ad_avr = avresample_alloc_context(); else avresample_close(ad->ad_avr); av_opt_set_int(ad->ad_avr, "in_sample_fmt", ad->ad_in_sample_format, 0); av_opt_set_int(ad->ad_avr, "in_sample_rate", ad->ad_in_sample_rate, 0); av_opt_set_int(ad->ad_avr, "in_channel_layout", ad->ad_in_channel_layout, 0); av_opt_set_int(ad->ad_avr, "out_sample_fmt", ad->ad_out_sample_format, 0); av_opt_set_int(ad->ad_avr, "out_sample_rate", ad->ad_out_sample_rate, 0); av_opt_set_int(ad->ad_avr, "out_channel_layout", ad->ad_out_channel_layout, 0); char buf1[128]; char buf2[128]; av_get_channel_layout_string(buf1, sizeof(buf1), -1, ad->ad_in_channel_layout); av_get_channel_layout_string(buf2, sizeof(buf2), -1, ad->ad_out_channel_layout); TRACE(TRACE_DEBUG, "Audio", "Converting from [%s %dHz %s] to [%s %dHz %s]", buf1, ad->ad_in_sample_rate, av_get_sample_fmt_name(ad->ad_in_sample_format), buf2, ad->ad_out_sample_rate, av_get_sample_fmt_name(ad->ad_out_sample_format)); if(avresample_open(ad->ad_avr)) { TRACE(TRACE_ERROR, "Audio", "Unable to open resampler"); avresample_free(&ad->ad_avr); } prop_set(mp->mp_prop_ctrl, "canAdjustVolume", PROP_SET_INT, 1); if(ac->ac_set_volume != NULL) ac->ac_set_volume(ad, ad->ad_vol_scale); } if(ad->ad_avr != NULL) { avresample_convert(ad->ad_avr, NULL, 0, 0, frame->data, frame->linesize[0], frame->nb_samples); } else { int delay = 1000000LL * frame->nb_samples / frame->sample_rate; usleep(delay); } } } }
static void audio_process_audio(audio_decoder_t *ad, media_buf_t *mb) { const audio_class_t *ac = ad->ad_ac; AVFrame *frame = ad->ad_frame; media_pipe_t *mp = ad->ad_mp; media_queue_t *mq = &mp->mp_audio; int r; int got_frame; AVPacket avpkt; int offset = 0; if(mb->mb_skip || mb->mb_stream != mq->mq_stream) return; while(offset < mb->mb_size) { if(mb->mb_cw == NULL) { frame->sample_rate = mb->mb_rate; frame->format = AV_SAMPLE_FMT_S16; switch(mb->mb_channels) { case 1: frame->channel_layout = AV_CH_LAYOUT_MONO; frame->nb_samples = mb->mb_size / 2; break; case 2: frame->channel_layout = AV_CH_LAYOUT_STEREO; frame->nb_samples = mb->mb_size / 4; break; default: abort(); } frame->data[0] = mb->mb_data; frame->linesize[0] = 0; r = mb->mb_size; got_frame = 1; } else { media_codec_t *mc = mb->mb_cw; AVCodecContext *ctx = mc->ctx; if(mc->codec_id != ad->ad_in_codec_id) { AVCodec *codec = avcodec_find_decoder(mc->codec_id); TRACE(TRACE_DEBUG, "audio", "Codec changed to %s", codec ? codec->name : "???"); ad->ad_in_codec_id = mc->codec_id; audio_cleanup_spdif_muxer(ad); if(ac->ac_check_passthru != NULL && codec != NULL && ac->ac_check_passthru(ad, mc->codec_id)) { audio_setup_spdif_muxer(ad, codec, mq); } } av_init_packet(&avpkt); avpkt.data = mb->mb_data + offset; avpkt.size = mb->mb_size - offset; if(ad->ad_spdif_muxer != NULL) { av_write_frame(ad->ad_spdif_muxer, &avpkt); avio_flush(ad->ad_spdif_muxer->pb); ad->ad_pts = mb->mb_pts; ad->ad_epoch = mb->mb_epoch; return; } if(ctx == NULL) { AVCodec *codec = avcodec_find_decoder(mc->codec_id); assert(codec != NULL); // Checked in libav.c ctx = mc->ctx = avcodec_alloc_context3(codec); if(ad->ad_stereo_downmix) ctx->request_channels = 2; if(avcodec_open2(mc->ctx, codec, NULL) < 0) { av_freep(&mc->ctx); return; } } r = avcodec_decode_audio4(ctx, frame, &got_frame, &avpkt); if(r < 0) return; if(frame->sample_rate == 0) { frame->sample_rate = ctx->sample_rate; if(frame->sample_rate == 0 && mb->mb_cw->fmt_ctx) frame->sample_rate = mb->mb_cw->fmt_ctx->sample_rate; if(frame->sample_rate == 0) return; } if(frame->channel_layout == 0) { switch(ctx->channels) { case 1: frame->channel_layout = AV_CH_LAYOUT_MONO; break; case 2: frame->channel_layout = AV_CH_LAYOUT_STEREO; break; default: return; } } if(mp->mp_stats) mp_set_mq_meta(mq, ctx->codec, ctx); } if(offset == 0 && mb->mb_pts != AV_NOPTS_VALUE) { int od = 0, id = 0; if(ad->ad_avr != NULL) { od = avresample_available(ad->ad_avr) * 1000000LL / ad->ad_out_sample_rate; id = avresample_get_delay(ad->ad_avr) * 1000000LL / frame->sample_rate; } ad->ad_pts = mb->mb_pts - od - id; ad->ad_epoch = mb->mb_epoch; // printf("od=%-20d id=%-20d PTS=%-20ld oPTS=%-20ld\n", // od, id, mb->mb_pts, pts); if(mb->mb_drive_clock) mp_set_current_time(mp, mb->mb_pts - ad->ad_delay, mb->mb_epoch, mb->mb_delta); } offset += r; if(got_frame) { if(frame->sample_rate != ad->ad_in_sample_rate || frame->format != ad->ad_in_sample_format || frame->channel_layout != ad->ad_in_channel_layout) { ad->ad_in_sample_rate = frame->sample_rate; ad->ad_in_sample_format = frame->format; ad->ad_in_channel_layout = frame->channel_layout; ac->ac_reconfig(ad); if(ad->ad_avr == NULL) ad->ad_avr = avresample_alloc_context(); else avresample_close(ad->ad_avr); av_opt_set_int(ad->ad_avr, "in_sample_fmt", ad->ad_in_sample_format, 0); av_opt_set_int(ad->ad_avr, "in_sample_rate", ad->ad_in_sample_rate, 0); av_opt_set_int(ad->ad_avr, "in_channel_layout", ad->ad_in_channel_layout, 0); av_opt_set_int(ad->ad_avr, "out_sample_fmt", ad->ad_out_sample_format, 0); av_opt_set_int(ad->ad_avr, "out_sample_rate", ad->ad_out_sample_rate, 0); av_opt_set_int(ad->ad_avr, "out_channel_layout", ad->ad_out_channel_layout, 0); char buf1[128]; char buf2[128]; av_get_channel_layout_string(buf1, sizeof(buf1), -1, ad->ad_in_channel_layout); av_get_channel_layout_string(buf2, sizeof(buf2), -1, ad->ad_out_channel_layout); TRACE(TRACE_DEBUG, "Audio", "Converting from [%s %dHz %s] to [%s %dHz %s]", buf1, ad->ad_in_sample_rate, av_get_sample_fmt_name(ad->ad_in_sample_format), buf2, ad->ad_out_sample_rate, av_get_sample_fmt_name(ad->ad_out_sample_format)); if(avresample_open(ad->ad_avr)) { TRACE(TRACE_ERROR, "AudioQueue", "Unable to open resampler"); avresample_free(&ad->ad_avr); } if(ac->ac_set_volume != NULL) { prop_set(mp->mp_prop_ctrl, "canAdjustVolume", PROP_SET_INT, 1); ac->ac_set_volume(ad, ad->ad_vol_scale); } } if(ad->ad_avr != NULL) avresample_convert(ad->ad_avr, NULL, 0, 0, frame->data, frame->linesize[0], frame->nb_samples); } } }