int audio_thr(LPVOID lpParam) { int iRet = -1; //音频测试,播放文件显示波形 AVFormatContext * pFmtCtx = NULL; AVFormatContext * pFOutmtCtx = NULL; AVInputFormat * pAudioInputFmt = NULL; AVOutputFormat * pAudioOutputFmt = NULL; AVCodecContext * pOutputCodecCtx = NULL; AVPacket * pAudioPacket = NULL; int iAudioIndex = -1; int data_size = 0; int resampled_data_size = 0; uint8_t * out_buffer = 0; int64_t dec_channel_layout = 0; double pts; CLS_DlgStreamPusher* pThis = (CLS_DlgStreamPusher*)lpParam; if (pThis == NULL || pThis->m_pStreamInfo == NULL){ TRACE("audio_thr--pThis == NULL || pThis->m_pStreamInfo == NULL\n"); return iRet; } struct_stream_info* strct_stream_info = pThis->m_pStreamInfo; pAudioInputFmt = av_find_input_format("dshow"); if (pAudioInputFmt == NULL){ TRACE("pAudioInputFmt == NULL\n"); return iRet; } char* psDevName = pThis->GetDeviceName(n_Audio); if (psDevName == NULL){ TRACE("audio_thr--psDevName == NULL"); return iRet; } if (avformat_open_input(&pFmtCtx, psDevName, pAudioInputFmt, NULL) != 0){ TRACE("avformat_open_input err!\n"); goto END; } if (avformat_find_stream_info(pFmtCtx, NULL) < 0){ TRACE("avformat_find_stream_info(pFmtCtx, NULL) < 0\n"); goto END; } for (int i = 0; i < pFmtCtx->nb_streams; i++){ if (pFmtCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO){ iAudioIndex = i; AVCodec *tmpCodec = avcodec_find_decoder(pFmtCtx->streams[i]->codec->codec_id); if (0 > avcodec_open2(pFmtCtx->streams[i]->codec, tmpCodec, NULL)){ TRACE("can not find or open decoder!\n"); } break; } } //找到音频流信息 strct_stream_info->m_pAudioStream = pFmtCtx->streams[iAudioIndex]; if (strct_stream_info->m_pAudioStream == NULL){ TRACE("strct_stream_info->m_pAudioStream == NULL\n"); goto END; } AVCodecContext *pAudioDec = strct_stream_info->m_pAudioStream->codec; if (NULL == pAudioDec){ TRACE("NULL == pAudioDec\n"); goto END; } AVCodec* audio_encoder = avcodec_find_encoder(AV_CODEC_ID_AAC); if (audio_encoder == NULL){ TRACE("audio_encoder == NULL\r\n"); goto END; } pOutputCodecCtx = avcodec_alloc_context3(audio_encoder); if (pOutputCodecCtx == NULL){ TRACE("pOutputCodecCtx == NULL"); goto END; } pOutputCodecCtx->sample_rate = pFmtCtx->streams[0]->codec->sample_rate; pOutputCodecCtx->channel_layout = AV_CH_LAYOUT_STEREO; pOutputCodecCtx->channels = av_get_channel_layout_nb_channels(pOutputCodecCtx->channel_layout); pOutputCodecCtx->sample_fmt = audio_encoder->sample_fmts[0]; pOutputCodecCtx->codec = audio_encoder; pOutputCodecCtx->codec_tag = 0; if (avcodec_open2(pOutputCodecCtx, pOutputCodecCtx->codec, 0) < 0){ //编码器打开失败,退出程序 TRACE("音频编码器打开失败!\n"); goto END; } //SDL_AudioSpec int out_nb_samples = AUDIO_BUF_SIZE; AVSampleFormat out_sample_fmt = AV_SAMPLE_FMT_S16; int out_buffer_size = av_samples_get_buffer_size(NULL, pOutputCodecCtx->channels, out_nb_samples, out_sample_fmt, 1); SDL_AudioSpec wanted_spec, spec; wanted_spec.freq = pOutputCodecCtx->sample_rate; wanted_spec.format = AUDIO_S16SYS; wanted_spec.channels = pOutputCodecCtx->channels; wanted_spec.silence = 0; wanted_spec.samples = out_nb_samples; wanted_spec.callback = fill_audio;//&CLS_DlgStreamPusher:: wanted_spec.userdata = strct_stream_info; strct_stream_info->m_content_out_channels = pOutputCodecCtx->channels; if (SDL_OpenAudio(&wanted_spec, &spec)<0){ TRACE("can't open audio.\n"); goto END; } int audio_hw_buf_size = spec.size; if (audio_hw_buf_size < 0){ TRACE("audio_hw_buf_size < 0\n"); return -1; } strct_stream_info->m_audio_src.fmt = AV_SAMPLE_FMT_S16; strct_stream_info->m_audio_src.freq = spec.freq; strct_stream_info->m_audio_src.channel_layout = pOutputCodecCtx->channel_layout; strct_stream_info->m_audio_src.channels = spec.channels; strct_stream_info->m_audio_hw_buf_size = audio_hw_buf_size; strct_stream_info->m_audio_tgt = strct_stream_info->m_audio_src; AVPacket pkt; out_buffer = (uint8_t *)av_malloc(MAX_AUDIO_FRAME_SIZE * 2); strct_stream_info->m_audio_refresh_tid = SDL_CreateThread(audio_refresh_thread, NULL, strct_stream_info); while (av_read_frame(pFmtCtx, &pkt) == 0 && _kbhit() == 0){ if (!pThis->m_blAudioShow){ break; } if (pkt.stream_index != iAudioIndex){ continue; } if (!strct_stream_info->m_pAudioFrame) { if (!(strct_stream_info->m_pAudioFrame = avcodec_alloc_frame())){ TRACE("!(strct_stream_info->m_pAudioFrame = avcodec_alloc_frame())\n"); goto END; } } else{ avcodec_get_frame_defaults(strct_stream_info->m_pAudioFrame); } int gotframe = -1; strct_stream_info->m_pAudioFrame = av_frame_alloc(); if (avcodec_decode_audio4(pAudioDec, strct_stream_info->m_pAudioFrame, &gotframe, &pkt) < 0){ av_frame_free(&strct_stream_info->m_pAudioFrame); TRACE("can not decoder a frame\n"); break; } av_free_packet(&pkt); if (!gotframe){ //没有获取到数据,继续下一次 continue; } strct_stream_info->m_pAudioFrame->nb_samples = 1024;//这里暂时写死值 data_size = av_samples_get_buffer_size(NULL, pOutputCodecCtx->channels, strct_stream_info->m_pAudioFrame->nb_samples, pOutputCodecCtx->sample_fmt, 1); dec_channel_layout = (pOutputCodecCtx->channel_layout && pOutputCodecCtx->channels == av_get_channel_layout_nb_channels(pOutputCodecCtx->channel_layout)) ? pOutputCodecCtx->channel_layout : av_get_default_channel_layout(pOutputCodecCtx->channels); //wanted_nb_samples = SynAudio(strct_stream_info, strct_stream_info->m_pAudioFrame->nb_samples); /*if (pOutputCodecCtx->sample_fmt != strct_stream_info->m_audio_src.fmt || dec_channel_layout != strct_stream_info->m_audio_src.channel_layout || pOutputCodecCtx->sample_rate != strct_stream_info->m_audio_src.freq){*/ swr_free(&strct_stream_info->m_audio_swr_ctx); strct_stream_info->m_audio_swr_ctx = swr_alloc_set_opts(NULL, strct_stream_info->m_audio_tgt.channel_layout, strct_stream_info->m_audio_tgt.fmt, strct_stream_info->m_audio_tgt.freq, dec_channel_layout, pOutputCodecCtx->sample_fmt, pOutputCodecCtx->sample_rate, 0, NULL); if (!strct_stream_info->m_audio_swr_ctx || swr_init(strct_stream_info->m_audio_swr_ctx) < 0){ TRACE("!pThis->m_pStreamInfstrct_stream_infoo->m_audio_swr_ctx || swr_init(strct_stream_info->m_audio_swr_ctx) < 0"); break; } strct_stream_info->m_audio_src.channel_layout = dec_channel_layout; strct_stream_info->m_audio_src.channels = pOutputCodecCtx->channels; strct_stream_info->m_audio_src.freq = pOutputCodecCtx->sample_rate; strct_stream_info->m_audio_src.fmt = pOutputCodecCtx->sample_fmt; //} if (NULL != strct_stream_info->m_audio_swr_ctx){ const uint8_t **in = (const uint8_t **)strct_stream_info->m_pAudioFrame->extended_data; uint8_t *out[] = { strct_stream_info->m_audio_buf2 }; int out_count = sizeof(strct_stream_info->m_audio_buf2) / strct_stream_info->m_audio_tgt.channels / av_get_bytes_per_sample(strct_stream_info->m_audio_tgt.fmt); int iRet = swr_convert(strct_stream_info->m_audio_swr_ctx, out, out_count, in, strct_stream_info->m_pAudioFrame->nb_samples); if (iRet < 0){ TRACE("swr_convert < 0\n"); break; } if (iRet == out_count) { TRACE("warning: audio buffer is probably too small\n"); swr_init(strct_stream_info->m_audio_swr_ctx); } strct_stream_info->m_audio_buf = strct_stream_info->m_audio_buf2; resampled_data_size = iRet * strct_stream_info->m_audio_tgt.channels * av_get_bytes_per_sample(strct_stream_info->m_audio_tgt.fmt); } else{ strct_stream_info->m_audio_buf = strct_stream_info->m_pAudioFrame->data[0]; resampled_data_size = data_size; } /* if no pts, then compute it */ pts = strct_stream_info->m_audio_clock; //*pts_ptr = pts; strct_stream_info->m_audio_clock += (double)data_size / (pAudioDec->channels * pAudioDec->sample_rate * av_get_bytes_per_sample(pAudioDec->sample_fmt)); #ifdef DEBUG { static double last_clock; /*printf("audio: delay=%0.3f clock=%0.3f pts=%0.3f\n", is->audio_clock - last_clock, is->audio_clock, pts);*/ last_clock = strct_stream_info->m_audio_clock; } #endif //FIX:FLAC,MP3,AAC Different number of samples /*if (wanted_spec.samples != strct_stream_info->m_pAudioFrame->nb_samples){ SDL_CloseAudio(); out_nb_samples = strct_stream_info->m_pAudioFrame->nb_samples; out_buffer_size = av_samples_get_buffer_size(NULL, pOutputCodecCtx->channels, out_nb_samples, out_sample_fmt, 1); wanted_spec.samples = out_nb_samples; SDL_OpenAudio(&wanted_spec, NULL); }*/ //设置PCM数据 TRACE("----out_buffer_size---is [%ld]\n",out_buffer_size); audio_chunk = (Uint8 *)out_buffer; audio_len = out_buffer_size; audio_pos = audio_chunk; strct_stream_info->m_aduio_pkt_size = resampled_data_size;//audio_len;// av_free_packet(&pkt); //写PCM进行test if (1){ FILE *p = NULL; fopen_s(&p, "test.pcm", "a+b"); if (p == NULL){ continue; } int tempLenght = 2 * strct_stream_info->m_pAudioFrame->nb_samples;//由于实验中知道这是16位深,所以才这么写 uint8_t *tmpPtr = strct_stream_info->m_pAudioFrame->data[0]; if (NULL != p) { while (tempLenght > 0) { size_t temp = fwrite(tmpPtr, 1, tempLenght, p); tmpPtr += temp; tempLenght = tempLenght - temp; } fclose(p); } } SDL_PauseAudio(0); //while (audio_len > 0){ // //Wait until finish // SDL_Delay(1); //} //if (pFmtCtx->streams[iAudioIndex]->codec->sample_fmt != pOutputCodecCtx->sample_fmt // || pFmtCtx->streams[iAudioIndex]->codec->channels != pOutputCodecCtx->channels // || pFmtCtx->streams[iAudioIndex]->codec->sample_rate != pOutputCodecCtx->sample_rate){ // //TODO如果输入和输出的音频格式不一样 需要重采样,这里是一样的就没做 //} //av_audio_fifo_realloc(fifo, av_audio_fifo_size(fifo) + frame->nb_samples); //av_audio_fifo_write(fifo, (void **)frame->data, frame->nb_samples); ////循环读取数据,直到buf里数据采样数不够 //while (av_audio_fifo_size(fifo) >= (pOutputCodecCtx->frame_size > 0 ? pOutputCodecCtx->frame_size : AUDIO_BUF_SIZE)) //{ // av_frame_free(&frame); // frame = av_frame_alloc(); // frame->nb_samples = pOutputCodecCtx->frame_size>0 ? pOutputCodecCtx->frame_size : AUDIO_BUF_SIZE; // frame->channel_layout = pOutputCodecCtx->channel_layout; // frame->format = pOutputCodecCtx->sample_fmt; // frame->sample_rate = pOutputCodecCtx->sample_rate; // av_frame_get_buffer(frame, 0); // av_audio_fifo_read(fifo, (void **)frame->data, (pOutputCodecCtx->frame_size > 0 ? pOutputCodecCtx->frame_size : AUDIO_BUF_SIZE)); // av_init_packet(&pkt_out); // //frame->pts = pFrame->pts; // int got_picture = -1; // pkt_out.data = NULL; // pkt_out.size = 0; // if (avcodec_encode_audio2(pOutputCodecCtx, &pkt_out, frame, &got_picture) < 0){ // printf("can not decoder a frame"); // } // av_frame_free(&frame); // if (got_picture) // { // pkt_out.pts = frameIndex * pOutputCodecCtx->frame_size; // pkt_out.dts = frameIndex * pOutputCodecCtx->frame_size; // pkt_out.duration = pOutputCodecCtx->frame_size; // //TODO将编码结果后续做合成处理[pkt_out] // if (pFile != NULL){ // /*fwrite((uint8_t *)pDlg->m_streamstate->audio_buf + pDlg->m_streamstate->audio_buf_index, 1, len1, pFile);*/ // } // frameIndex++; // } //} } iRet = 1; END: //swr_free(&au_convert_ctx); SDL_CloseAudio(); SDL_Quit(); av_free(out_buffer); avcodec_close(pOutputCodecCtx); return iRet; }
static bool reinitialize_coder(struct libavcodec_codec_state *s, struct audio_desc desc) { av_freep(&s->samples); pthread_mutex_lock(s->libav_global_lock); avcodec_close(s->codec_ctx); pthread_mutex_unlock(s->libav_global_lock); /* put sample parameters */ s->codec_ctx->bit_rate = 64000; s->codec_ctx->sample_rate = desc.sample_rate; s->change_bps_to = 0; switch(desc.bps) { case 1: s->codec_ctx->sample_fmt = AV_SAMPLE_FMT_U8; break; case 2: s->codec_ctx->sample_fmt = AV_SAMPLE_FMT_S16; break; case 3: s->change_bps_to = 4; case 4: s->codec_ctx->sample_fmt = AV_SAMPLE_FMT_S32; break; } if(!check_sample_fmt(s->codec, s->codec_ctx->sample_fmt)) { s->codec_ctx->sample_fmt = s->codec->sample_fmts[0]; s->change_bps_to = av_get_bytes_per_sample(s->codec_ctx->sample_fmt); } s->codec_ctx->channels = 1; s->codec_ctx->channel_layout = AV_CH_LAYOUT_MONO; pthread_mutex_lock(s->libav_global_lock); /* open it */ if (avcodec_open2(s->codec_ctx, s->codec, NULL) < 0) { fprintf(stderr, "Could not open codec\n"); pthread_mutex_unlock(s->libav_global_lock); return false; } pthread_mutex_unlock(s->libav_global_lock); if(s->codec->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE) { s->codec_ctx->frame_size = 1; } s->av_frame->nb_samples = s->codec_ctx->frame_size; s->av_frame->format = s->codec_ctx->sample_fmt; s->av_frame->channel_layout = AV_CH_LAYOUT_MONO; int channels = 1; /* the codec gives us the frame size, in samples, * we calculate the size of the samples buffer in bytes */ int buffer_size = av_samples_get_buffer_size(NULL, channels, s->codec_ctx->frame_size, s->codec_ctx->sample_fmt, 0); s->samples = av_malloc(buffer_size); if (!s->samples) { fprintf(stderr, "could not allocate %d bytes for samples buffer\n", buffer_size); return false; } /* setup the data pointers in the AVFrame */ int ret = avcodec_fill_audio_frame(s->av_frame, channels, s->codec_ctx->sample_fmt, (const uint8_t*)s->samples, buffer_size, 0); if (ret < 0) { fprintf(stderr, "could not setup audio frame\n"); return false; } s->output_channel.sample_rate = desc.sample_rate; s->output_channel.bps = desc.bps; s->saved_desc = desc; return true; }
int THMovie::decodeAudioFrame(bool fFirst) { int iBytesConsumed = 0; int iSampleSize = 0; int iOutSamples; int iGotFrame = 0; bool fNewPacket = false; bool fFlushComplete = false; double dClockPts; int64_t iStreamPts; while(!iGotFrame && !m_fAborting) { if(!m_pAudioPacket || m_pAudioPacket->size == 0) { if(m_pAudioPacket) { m_pAudioPacket->data = m_pbAudioPacketData; m_pAudioPacket->size = m_iAudioPacketSize; av_packet_unref(m_pAudioPacket); av_free(m_pAudioPacket); m_pAudioPacket = nullptr; } m_pAudioPacket = m_pAudioQueue->pull(true); if(m_fAborting) { break; } m_pbAudioPacketData = m_pAudioPacket->data; m_iAudioPacketSize = m_pAudioPacket->size; if(m_pAudioPacket == nullptr) { fNewPacket = false; return -1; } fNewPacket = true; if(m_pAudioPacket->data == m_flushPacket->data) { avcodec_flush_buffers(m_pAudioCodecContext); fFlushComplete = false; } } if(fFirst) { iStreamPts = m_pAudioPacket->pts; if(iStreamPts != AV_NOPTS_VALUE) { //There is a time_base in m_pAudioCodecContext too, but that one is wrong. dClockPts = iStreamPts * av_q2d(m_pFormatContext->streams[m_iAudioStream]->time_base); m_iCurSyncPts = dClockPts; m_iCurSyncPtsSystemTime = SDL_GetTicks(); } fFirst = false; } while(m_pAudioPacket->size > 0 || (!m_pAudioPacket->data && fNewPacket)) { if(!m_audio_frame) { m_audio_frame = av_frame_alloc(); } else { av_frame_unref(m_audio_frame); } if(fFlushComplete) { break; } fNewPacket = false; iBytesConsumed = avcodec_decode_audio4(m_pAudioCodecContext, m_audio_frame, &iGotFrame, m_pAudioPacket); if(iBytesConsumed < 0) { m_pAudioPacket->size = 0; break; } m_pAudioPacket->data += iBytesConsumed; m_pAudioPacket->size -= iBytesConsumed; if(!iGotFrame) { if(m_pAudioPacket->data && (m_pAudioCodecContext->codec->capabilities & CODEC_CAP_DELAY)) { fFlushComplete = true; } } } } //over-estimate output samples iOutSamples = (int)av_rescale_rnd(m_audio_frame->nb_samples, m_iMixerFrequency, m_pAudioCodecContext->sample_rate, AV_ROUND_UP); iSampleSize = av_get_bytes_per_sample(AV_SAMPLE_FMT_S16) * iOutSamples * m_iMixerChannels; if(iSampleSize > m_iAudioBufferMaxSize) { if(m_iAudioBufferMaxSize > 0) { av_free(m_pbAudioBuffer); } m_pbAudioBuffer = (uint8_t*)av_malloc(iSampleSize); m_iAudioBufferMaxSize = iSampleSize; } #ifdef CORSIX_TH_USE_FFMPEG swr_convert(m_pAudioResampleContext, &m_pbAudioBuffer, iOutSamples, (const uint8_t**)&m_audio_frame->data[0], m_audio_frame->nb_samples); #elif defined(CORSIX_TH_USE_LIBAV) avresample_convert(m_pAudioResampleContext, &m_pbAudioBuffer, 0, iOutSamples, (uint8_t**)&m_audio_frame->data[0], 0, m_audio_frame->nb_samples); #endif return iSampleSize; }
/** @internal @This outputs audio buffers * * @param upipe description structure of the pipe * @param frame AVFrame structure * @param upump upump structure */ static void upipe_avcdec_output_audio(struct upipe *upipe, AVFrame *frame, struct upump *upump) { struct ubuf *ubuf; struct upipe_avcdec *upipe_avcdec = upipe_avcdec_from_upipe(upipe); struct uref *uref = frame->opaque; int bufsize = -1, avbufsize; size_t size = 0; uint8_t *buf; AVCodecContext *context = upipe_avcdec->context; /* fetch audio sample size (in case it has been reduced) */ avbufsize = av_samples_get_buffer_size(NULL, context->channels, frame->nb_samples, context->sample_fmt, 1); /* if uref has no attached ubuf (ie DR not supported) */ if (unlikely(!uref->ubuf)) { ubuf = ubuf_block_alloc(upipe_avcdec->ubuf_mgr, avbufsize); if (unlikely(!ubuf)) { upipe_throw_aerror(upipe); return; } ubuf_block_write(ubuf, 0, &bufsize, &buf); memcpy(buf, frame->data[0], bufsize); uref_attach_ubuf(uref, ubuf); } /* unmap, reduce block if needed */ uref_block_unmap(uref, 0); uref_block_size(uref, &size); if (unlikely(size != avbufsize)) { uref_block_resize(uref, 0, avbufsize); } /* TODO: set attributes/need a real ubuf_audio structure (?) */ if (!upipe_avcdec->output_flow) { #if 0 struct uref *outflow = uref_sound_flow_alloc_def(upipe_avcdec->uref_mgr, context->channels, av_get_bytes_per_sample(context->sample_fmt)); #else struct uref *outflow = uref_block_flow_alloc_def(upipe_avcdec->uref_mgr, "sound."); #endif uref_sound_flow_set_channels(outflow, context->channels); uref_sound_flow_set_sample_size(outflow, av_get_bytes_per_sample(context->sample_fmt)); uref_sound_flow_set_rate(outflow, context->sample_rate); upipe_avcdec_store_flow_def(upipe, outflow); } /* samples in uref */ uref_sound_flow_set_samples(uref, frame->nb_samples); /* index rap attribute */ upipe_avcdec_set_index_rap(upipe, uref); upipe_avcdec_output(upipe, uref, upump); }
int scan_metadata_ffmpeg(char *file, struct media_file_info *mfi) { AVFormatContext *ctx; AVDictionary *options; const struct metadata_map *extra_md_map; struct http_icy_metadata *icy_metadata; #if LIBAVCODEC_VERSION_MAJOR >= 55 || (LIBAVCODEC_VERSION_MAJOR == 54 && LIBAVCODEC_VERSION_MINOR >= 35) enum AVCodecID codec_id; enum AVCodecID video_codec_id; enum AVCodecID audio_codec_id; #else enum CodecID codec_id; enum CodecID video_codec_id; enum CodecID audio_codec_id; #endif AVStream *video_stream; AVStream *audio_stream; char *path; int mdcount; int i; int ret; ctx = NULL; options = NULL; path = strdup(file); #if LIBAVFORMAT_VERSION_MAJOR >= 54 || (LIBAVFORMAT_VERSION_MAJOR == 53 && LIBAVFORMAT_VERSION_MINOR >= 3) # ifndef HAVE_FFMPEG // Without this, libav is slow to probe some internet streams if (mfi->data_kind == DATA_KIND_HTTP) { ctx = avformat_alloc_context(); ctx->probesize = 64000; } # endif if (mfi->data_kind == DATA_KIND_HTTP) { free(path); ret = http_stream_setup(&path, file); if (ret < 0) return -1; av_dict_set(&options, "icy", "1", 0); mfi->artwork = ARTWORK_HTTP; } ret = avformat_open_input(&ctx, path, NULL, &options); if (options) av_dict_free(&options); #else ret = av_open_input_file(&ctx, path, NULL, 0, NULL); #endif if (ret != 0) { DPRINTF(E_WARN, L_SCAN, "Cannot open media file '%s': %s\n", path, strerror(AVUNERROR(ret))); free(path); return -1; } free(path); #if LIBAVFORMAT_VERSION_MAJOR >= 54 || (LIBAVFORMAT_VERSION_MAJOR == 53 && LIBAVFORMAT_VERSION_MINOR >= 3) ret = avformat_find_stream_info(ctx, NULL); #else ret = av_find_stream_info(ctx); #endif if (ret < 0) { DPRINTF(E_WARN, L_SCAN, "Cannot get stream info: %s\n", strerror(AVUNERROR(ret))); #if LIBAVFORMAT_VERSION_MAJOR >= 54 || (LIBAVFORMAT_VERSION_MAJOR == 53 && LIBAVFORMAT_VERSION_MINOR >= 21) avformat_close_input(&ctx); #else av_close_input_file(ctx); #endif return -1; } #if 0 /* Dump input format as determined by ffmpeg */ av_dump_format(ctx, 0, file, 0); #endif DPRINTF(E_DBG, L_SCAN, "File has %d streams\n", ctx->nb_streams); /* Extract codec IDs, check for video */ #if LIBAVCODEC_VERSION_MAJOR >= 55 || (LIBAVCODEC_VERSION_MAJOR == 54 && LIBAVCODEC_VERSION_MINOR >= 35) video_codec_id = AV_CODEC_ID_NONE; video_stream = NULL; audio_codec_id = AV_CODEC_ID_NONE; audio_stream = NULL; #else video_codec_id = CODEC_ID_NONE; video_stream = NULL; audio_codec_id = CODEC_ID_NONE; audio_stream = NULL; #endif for (i = 0; i < ctx->nb_streams; i++) { switch (ctx->streams[i]->codec->codec_type) { #if LIBAVCODEC_VERSION_MAJOR >= 53 || (LIBAVCODEC_VERSION_MAJOR == 52 && LIBAVCODEC_VERSION_MINOR >= 64) case AVMEDIA_TYPE_VIDEO: #else case CODEC_TYPE_VIDEO: #endif #if LIBAVFORMAT_VERSION_MAJOR >= 55 || (LIBAVFORMAT_VERSION_MAJOR == 54 && LIBAVFORMAT_VERSION_MINOR >= 6) if (ctx->streams[i]->disposition & AV_DISPOSITION_ATTACHED_PIC) { DPRINTF(E_DBG, L_SCAN, "Found embedded artwork (stream %d)\n", i); mfi->artwork = ARTWORK_EMBEDDED; break; } #endif // We treat these as audio no matter what if (mfi->compilation || (mfi->media_kind & (MEDIA_KIND_PODCAST | MEDIA_KIND_AUDIOBOOK))) break; if (!video_stream) { DPRINTF(E_DBG, L_SCAN, "File has video (stream %d)\n", i); mfi->has_video = 1; video_stream = ctx->streams[i]; video_codec_id = video_stream->codec->codec_id; } break; #if LIBAVCODEC_VERSION_MAJOR >= 53 || (LIBAVCODEC_VERSION_MAJOR == 52 && LIBAVCODEC_VERSION_MINOR >= 64) case AVMEDIA_TYPE_AUDIO: #else case CODEC_TYPE_AUDIO: #endif if (!audio_stream) { audio_stream = ctx->streams[i]; audio_codec_id = audio_stream->codec->codec_id; } break; default: break; } } #if LIBAVCODEC_VERSION_MAJOR >= 55 || (LIBAVCODEC_VERSION_MAJOR == 54 && LIBAVCODEC_VERSION_MINOR >= 35) if (audio_codec_id == AV_CODEC_ID_NONE) #else if (audio_codec_id == CODEC_ID_NONE) #endif { DPRINTF(E_DBG, L_SCAN, "File has no audio streams, discarding\n"); #if LIBAVFORMAT_VERSION_MAJOR >= 54 || (LIBAVFORMAT_VERSION_MAJOR == 53 && LIBAVFORMAT_VERSION_MINOR >= 21) avformat_close_input(&ctx); #else av_close_input_file(ctx); #endif return -1; } /* Common media information */ if (ctx->duration > 0) mfi->song_length = ctx->duration / (AV_TIME_BASE / 1000); /* ms */ if (ctx->bit_rate > 0) mfi->bitrate = ctx->bit_rate / 1000; else if (ctx->duration > AV_TIME_BASE) /* guesstimate */ mfi->bitrate = ((mfi->file_size * 8) / (ctx->duration / AV_TIME_BASE)) / 1000; DPRINTF(E_DBG, L_SCAN, "Duration %d ms, bitrate %d kbps\n", mfi->song_length, mfi->bitrate); /* Try to extract ICY metadata if http stream */ if (mfi->data_kind == DATA_KIND_HTTP) { icy_metadata = http_icy_metadata_get(ctx, 0); if (icy_metadata && icy_metadata->name) { DPRINTF(E_DBG, L_SCAN, "Found ICY metadata, name is '%s'\n", icy_metadata->name); if (mfi->title) free(mfi->title); if (mfi->artist) free(mfi->artist); if (mfi->album_artist) free(mfi->album_artist); mfi->title = strdup(icy_metadata->name); mfi->artist = strdup(icy_metadata->name); mfi->album_artist = strdup(icy_metadata->name); } if (icy_metadata && icy_metadata->description) { DPRINTF(E_DBG, L_SCAN, "Found ICY metadata, description is '%s'\n", icy_metadata->description); if (mfi->album) free(mfi->album); mfi->album = strdup(icy_metadata->description); } if (icy_metadata && icy_metadata->genre) { DPRINTF(E_DBG, L_SCAN, "Found ICY metadata, genre is '%s'\n", icy_metadata->genre); if (mfi->genre) free(mfi->genre); mfi->genre = strdup(icy_metadata->genre); } if (icy_metadata) http_icy_metadata_free(icy_metadata, 0); } /* Get some more information on the audio stream */ if (audio_stream) { if (audio_stream->codec->sample_rate != 0) mfi->samplerate = audio_stream->codec->sample_rate; /* Try sample format first */ #if LIBAVUTIL_VERSION_MAJOR >= 52 || (LIBAVUTIL_VERSION_MAJOR == 51 && LIBAVUTIL_VERSION_MINOR >= 4) mfi->bits_per_sample = 8 * av_get_bytes_per_sample(audio_stream->codec->sample_fmt); #elif LIBAVCODEC_VERSION_MAJOR >= 53 mfi->bits_per_sample = av_get_bits_per_sample_fmt(audio_stream->codec->sample_fmt); #else mfi->bits_per_sample = av_get_bits_per_sample_format(audio_stream->codec->sample_fmt); #endif if (mfi->bits_per_sample == 0) { /* Try codec */ mfi->bits_per_sample = av_get_bits_per_sample(audio_codec_id); } DPRINTF(E_DBG, L_SCAN, "samplerate %d, bps %d\n", mfi->samplerate, mfi->bits_per_sample); } /* Check codec */ extra_md_map = NULL; codec_id = (mfi->has_video) ? video_codec_id : audio_codec_id; switch (codec_id) { #if LIBAVCODEC_VERSION_MAJOR >= 55 || (LIBAVCODEC_VERSION_MAJOR == 54 && LIBAVCODEC_VERSION_MINOR >= 35) case AV_CODEC_ID_AAC: #else case CODEC_ID_AAC: #endif DPRINTF(E_DBG, L_SCAN, "AAC\n"); mfi->type = strdup("m4a"); mfi->codectype = strdup("mp4a"); mfi->description = strdup("AAC audio file"); break; #if LIBAVCODEC_VERSION_MAJOR >= 55 || (LIBAVCODEC_VERSION_MAJOR == 54 && LIBAVCODEC_VERSION_MINOR >= 35) case AV_CODEC_ID_ALAC: #else case CODEC_ID_ALAC: #endif DPRINTF(E_DBG, L_SCAN, "ALAC\n"); mfi->type = strdup("m4a"); mfi->codectype = strdup("alac"); mfi->description = strdup("Apple Lossless audio file"); break; #if LIBAVCODEC_VERSION_MAJOR >= 55 || (LIBAVCODEC_VERSION_MAJOR == 54 && LIBAVCODEC_VERSION_MINOR >= 35) case AV_CODEC_ID_FLAC: #else case CODEC_ID_FLAC: #endif DPRINTF(E_DBG, L_SCAN, "FLAC\n"); mfi->type = strdup("flac"); mfi->codectype = strdup("flac"); mfi->description = strdup("FLAC audio file"); extra_md_map = md_map_vorbis; break; #if LIBAVCODEC_VERSION_MAJOR >= 55 || (LIBAVCODEC_VERSION_MAJOR == 54 && LIBAVCODEC_VERSION_MINOR >= 35) case AV_CODEC_ID_MUSEPACK7: case AV_CODEC_ID_MUSEPACK8: #else case CODEC_ID_MUSEPACK7: case CODEC_ID_MUSEPACK8: #endif DPRINTF(E_DBG, L_SCAN, "Musepack\n"); mfi->type = strdup("mpc"); mfi->codectype = strdup("mpc"); mfi->description = strdup("Musepack audio file"); break; #if LIBAVCODEC_VERSION_MAJOR >= 55 || (LIBAVCODEC_VERSION_MAJOR == 54 && LIBAVCODEC_VERSION_MINOR >= 35) case AV_CODEC_ID_MPEG4: /* Video */ case AV_CODEC_ID_H264: #else case CODEC_ID_MPEG4: /* Video */ case CODEC_ID_H264: #endif DPRINTF(E_DBG, L_SCAN, "MPEG4 video\n"); mfi->type = strdup("m4v"); mfi->codectype = strdup("mp4v"); mfi->description = strdup("MPEG-4 video file"); extra_md_map = md_map_tv; break; #if LIBAVCODEC_VERSION_MAJOR >= 55 || (LIBAVCODEC_VERSION_MAJOR == 54 && LIBAVCODEC_VERSION_MINOR >= 35) case AV_CODEC_ID_MP3: #else case CODEC_ID_MP3: #endif DPRINTF(E_DBG, L_SCAN, "MP3\n"); mfi->type = strdup("mp3"); mfi->codectype = strdup("mpeg"); mfi->description = strdup("MPEG audio file"); extra_md_map = md_map_id3; break; #if LIBAVCODEC_VERSION_MAJOR >= 55 || (LIBAVCODEC_VERSION_MAJOR == 54 && LIBAVCODEC_VERSION_MINOR >= 35) case AV_CODEC_ID_VORBIS: #else case CODEC_ID_VORBIS: #endif DPRINTF(E_DBG, L_SCAN, "VORBIS\n"); mfi->type = strdup("ogg"); mfi->codectype = strdup("ogg"); mfi->description = strdup("Ogg Vorbis audio file"); extra_md_map = md_map_vorbis; break; #if LIBAVCODEC_VERSION_MAJOR >= 55 || (LIBAVCODEC_VERSION_MAJOR == 54 && LIBAVCODEC_VERSION_MINOR >= 35) case AV_CODEC_ID_WMAV1: case AV_CODEC_ID_WMAV2: case AV_CODEC_ID_WMAVOICE: #else case CODEC_ID_WMAV1: case CODEC_ID_WMAV2: case CODEC_ID_WMAVOICE: #endif DPRINTF(E_DBG, L_SCAN, "WMA Voice\n"); mfi->type = strdup("wma"); mfi->codectype = strdup("wmav"); mfi->description = strdup("WMA audio file"); break; #if LIBAVCODEC_VERSION_MAJOR >= 55 || (LIBAVCODEC_VERSION_MAJOR == 54 && LIBAVCODEC_VERSION_MINOR >= 35) case AV_CODEC_ID_WMAPRO: #else case CODEC_ID_WMAPRO: #endif DPRINTF(E_DBG, L_SCAN, "WMA Pro\n"); mfi->type = strdup("wmap"); mfi->codectype = strdup("wma"); mfi->description = strdup("WMA audio file"); break; #if LIBAVCODEC_VERSION_MAJOR >= 55 || (LIBAVCODEC_VERSION_MAJOR == 54 && LIBAVCODEC_VERSION_MINOR >= 35) case AV_CODEC_ID_WMALOSSLESS: #else case CODEC_ID_WMALOSSLESS: #endif DPRINTF(E_DBG, L_SCAN, "WMA Lossless\n"); mfi->type = strdup("wma"); mfi->codectype = strdup("wmal"); mfi->description = strdup("WMA audio file"); break; #if LIBAVCODEC_VERSION_MAJOR >= 55 || (LIBAVCODEC_VERSION_MAJOR == 54 && LIBAVCODEC_VERSION_MINOR >= 35) case AV_CODEC_ID_PCM_S16LE ... AV_CODEC_ID_PCM_F64LE: #else case CODEC_ID_PCM_S16LE ... CODEC_ID_PCM_F64LE: #endif if (strcmp(ctx->iformat->name, "aiff") == 0) { DPRINTF(E_DBG, L_SCAN, "AIFF\n"); mfi->type = strdup("aif"); mfi->codectype = strdup("aif"); mfi->description = strdup("AIFF audio file"); break; } else if (strcmp(ctx->iformat->name, "wav") == 0) { DPRINTF(E_DBG, L_SCAN, "WAV\n"); mfi->type = strdup("wav"); mfi->codectype = strdup("wav"); mfi->description = strdup("WAV audio file"); break; } /* WARNING: will fallthrough to default case, don't move */ /* FALLTHROUGH */ default: DPRINTF(E_DBG, L_SCAN, "Unknown codec 0x%x (video: %s), format %s (%s)\n", codec_id, (mfi->has_video) ? "yes" : "no", ctx->iformat->name, ctx->iformat->long_name); mfi->type = strdup("unkn"); mfi->codectype = strdup("unkn"); if (mfi->has_video) { mfi->description = strdup("Unknown video file format"); extra_md_map = md_map_tv; } else mfi->description = strdup("Unknown audio file format"); break; } mdcount = 0; if ((!ctx->metadata) && (!audio_stream->metadata) && (video_stream && !video_stream->metadata)) { DPRINTF(E_WARN, L_SCAN, "ffmpeg reports no metadata\n"); goto skip_extract; } if (extra_md_map) { ret = extract_metadata(mfi, ctx, audio_stream, video_stream, extra_md_map); mdcount += ret; DPRINTF(E_DBG, L_SCAN, "Picked up %d tags with extra md_map\n", ret); } ret = extract_metadata(mfi, ctx, audio_stream, video_stream, md_map_generic); mdcount += ret; DPRINTF(E_DBG, L_SCAN, "Picked up %d tags with generic md_map, %d tags total\n", ret, mdcount); /* fix up TV metadata */ if (mfi->media_kind == 10) { /* I have no idea why this is, but iTunes reports a media kind of 64 for stik==10 (?!) */ mfi->media_kind = MEDIA_KIND_TVSHOW; } /* Unspecified video files are "Movies", media_kind 2 */ else if (mfi->has_video == 1) { mfi->media_kind = MEDIA_KIND_MOVIE; } skip_extract: #if LIBAVFORMAT_VERSION_MAJOR >= 54 || (LIBAVFORMAT_VERSION_MAJOR == 53 && LIBAVFORMAT_VERSION_MINOR >= 21) avformat_close_input(&ctx); #else av_close_input_file(ctx); #endif if (mdcount == 0) DPRINTF(E_WARN, L_SCAN, "ffmpeg/libav could not extract any metadata\n"); /* Just in case there's no title set ... */ if (mfi->title == NULL) mfi->title = strdup(mfi->fname); /* All done */ return 0; }
int swri_rematrix(SwrContext *s, AudioData *out, AudioData *in, int len, int mustcopy){ int out_i, in_i, i, j; int len1 = 0; int off = 0; if(s->mix_any_f) { s->mix_any_f(out->ch, (const uint8_t **)in->ch, s->native_matrix, len); return 0; } if(s->mix_2_1_simd || s->mix_1_1_simd){ len1= len&~15; off = len1 * out->bps; } av_assert0(!s->out_ch_layout || out->ch_count == av_get_channel_layout_nb_channels(s->out_ch_layout)); av_assert0(!s-> in_ch_layout || in ->ch_count == av_get_channel_layout_nb_channels(s-> in_ch_layout)); for(out_i=0; out_i<out->ch_count; out_i++){ switch(s->matrix_ch[out_i][0]){ case 0: if(mustcopy) memset(out->ch[out_i], 0, len * av_get_bytes_per_sample(s->int_sample_fmt)); break; case 1: in_i= s->matrix_ch[out_i][1]; if(s->matrix[out_i][in_i]!=1.0){ if(s->mix_1_1_simd && len1) s->mix_1_1_simd(out->ch[out_i] , in->ch[in_i] , s->native_simd_matrix, in->ch_count*out_i + in_i, len1); if(len != len1) s->mix_1_1_f (out->ch[out_i]+off, in->ch[in_i]+off, s->native_matrix, in->ch_count*out_i + in_i, len-len1); }else if(mustcopy){ memcpy(out->ch[out_i], in->ch[in_i], len*out->bps); }else{ out->ch[out_i]= in->ch[in_i]; } break; case 2: { int in_i1 = s->matrix_ch[out_i][1]; int in_i2 = s->matrix_ch[out_i][2]; if(s->mix_2_1_simd && len1) s->mix_2_1_simd(out->ch[out_i] , in->ch[in_i1] , in->ch[in_i2] , s->native_simd_matrix, in->ch_count*out_i + in_i1, in->ch_count*out_i + in_i2, len1); else s->mix_2_1_f (out->ch[out_i] , in->ch[in_i1] , in->ch[in_i2] , s->native_matrix, in->ch_count*out_i + in_i1, in->ch_count*out_i + in_i2, len1); if(len != len1) s->mix_2_1_f (out->ch[out_i]+off, in->ch[in_i1]+off, in->ch[in_i2]+off, s->native_matrix, in->ch_count*out_i + in_i1, in->ch_count*out_i + in_i2, len-len1); break;} default: if(s->int_sample_fmt == AV_SAMPLE_FMT_FLTP){ for(i=0; i<len; i++){ float v=0; for(j=0; j<s->matrix_ch[out_i][0]; j++){ in_i= s->matrix_ch[out_i][1+j]; v+= ((float*)in->ch[in_i])[i] * s->matrix_flt[out_i][in_i]; } ((float*)out->ch[out_i])[i]= v; } }else if(s->int_sample_fmt == AV_SAMPLE_FMT_DBLP){ for(i=0; i<len; i++){ double v=0; for(j=0; j<s->matrix_ch[out_i][0]; j++){ in_i= s->matrix_ch[out_i][1+j]; v+= ((double*)in->ch[in_i])[i] * s->matrix[out_i][in_i]; } ((double*)out->ch[out_i])[i]= v; } }else{ for(i=0; i<len; i++){ int v=0; for(j=0; j<s->matrix_ch[out_i][0]; j++){ in_i= s->matrix_ch[out_i][1+j]; v+= ((int16_t*)in->ch[in_i])[i] * s->matrix32[out_i][in_i]; } ((int16_t*)out->ch[out_i])[i]= (v + 16384)>>15; } } } } return 0; }
int audio_decode_frame(VideoState *is, double *pts_ptr) { int len1, data_size = 0, n; AVPacket *pkt = &is->audio_pkt; double pts; uint8_t *out[] = {is->audio_buf}; int64_t wanted_channel_layout = 0; wanted_channel_layout = is->audio_st->codec->channel_layout; SwrContext* t_audio_conv = swr_alloc_set_opts(NULL, wanted_channel_layout,AV_SAMPLE_FMT_S16,is->audio_st->codec->sample_rate, wanted_channel_layout,is->audio_st->codec->sample_fmt, is->audio_st->codec->sample_rate, 0,NULL); swr_init(t_audio_conv); for(;;) { while(is->audio_pkt_size > 0) { int got_frame = 0; int t_audio_size= 0; len1 = avcodec_decode_audio4(is->audio_st->codec, &is->audio_frame, &got_frame, pkt); if(len1 < 0) { /* if error, skip frame */ is->audio_pkt_size = 0; break; } if (got_frame) { int size1 = av_get_bytes_per_sample(AV_SAMPLE_FMT_S16); int len = swr_convert(t_audio_conv, out, (MAX_AUDIO_FRAME_SIZE * 3) / 2/is->audio_st->codec->channels/size1, (const uint8_t **)is->audio_frame.extended_data, is->audio_frame.nb_samples); t_audio_size = len * is->audio_st->codec->channels * av_get_bytes_per_sample(AV_SAMPLE_FMT_S16); //av_packet_unref(pkt); swr_free(&t_audio_conv); //return len; } is->audio_pkt_data += len1; is->audio_pkt_size -= len1; //if(data_size <= 0) { if(t_audio_size <= 0) { /* No data yet, get more frames */ continue; } pts = is->audio_clock; *pts_ptr = pts; n = 2*is->audio_st->codec->channels; is->audio_clock += (double)data_size / (double)(n * is->audio_st->codec->sample_rate); /* We have data, return it and come back for more later */ //return data_size; return t_audio_size; } if(pkt->data) av_free_packet(pkt); if(is->quit) { return -1; } /* next packet */ if(packet_queue_get(&is->audioq, pkt, 1) < 0) { return -1; } is->audio_pkt_data = pkt->data; is->audio_pkt_size = pkt->size; /* if update, update the audio clock w/pts */ if(pkt->pts != AV_NOPTS_VALUE) { is->audio_clock = av_q2d(is->audio_st->time_base)*pkt->pts; } } // // for(;;) { // while(is->audio_pkt_size > 0) { // int got_frame; // len1 = avcodec_decode_audio4(is->audio_st->codec, &is->audio_frame, &got_frame, pkt); // if(len1 < 0) { // /* if error, skip frame */ // is->audio_pkt_size = 0; // break; // } // if (got_frame) // { // data_size = // av_samples_get_buffer_size // ( // NULL, // is->audio_st->codec->channels, // is->audio_frame.nb_samples, // is->audio_st->codec->sample_fmt, // 1 // ); // memcpy(is->audio_buf, is->audio_frame.data[0], data_size); // } // is->audio_pkt_data += len1; // is->audio_pkt_size -= len1; // if(data_size <= 0) { // /* No data yet, get more frames */ // continue; // } // pts = is->audio_clock; // *pts_ptr = pts; // n = 2 * is->audio_st->codec->channels; // is->audio_clock += (double)data_size / // (double)(n * is->audio_st->codec->sample_rate); // // /* We have data, return it and come back for more later */ // return data_size; // } // if(pkt->data) // av_free_packet(pkt); // // if(is->quit) { // return -1; // } // /* next packet */ // if(packet_queue_get(&is->audioq, pkt, 1) < 0) { // return -1; // } // is->audio_pkt_data = pkt->data; // is->audio_pkt_size = pkt->size; // /* if update, update the audio clock w/pts */ // if(pkt->pts != AV_NOPTS_VALUE) { // is->audio_clock = av_q2d(is->audio_st->time_base)*pkt->pts; // } // // } return 0; }
int AudioLoader::decode_audio_frame(AVCodecContext* audioCtx, float* output, int* outputSize, AVPacket* packet) { // _dataSize input = number of bytes available for write in buff // output = number of bytes actually written (actual: FLT data) //E_DEBUG(EAlgorithm, "decode_audio_frame, available bytes in buffer = " << _dataSize); int gotFrame = 0; av_frame_unref(_decodedFrame); //avcodec_get_frame_defaults(_decodedFrame); int len = avcodec_decode_audio4(audioCtx, _decodedFrame, &gotFrame, packet); if (len < 0) return len; // error handling should be done outside if (gotFrame) { int inputSamples = _decodedFrame->nb_samples; int inputPlaneSize = av_samples_get_buffer_size(NULL, _nChannels, inputSamples, audioCtx->sample_fmt, 1); int outputPlaneSize = av_samples_get_buffer_size(NULL, _nChannels, inputSamples, AV_SAMPLE_FMT_FLT, 1); // the size of the output buffer in samples int outputBufferSamples = *outputSize / (av_get_bytes_per_sample(AV_SAMPLE_FMT_FLT) * _nChannels); if (outputBufferSamples < inputSamples) { // this should never happen, throw exception here throw EssentiaException("AudioLoader: Insufficient buffer size for format conversion"); } if (audioCtx->sample_fmt == AV_SAMPLE_FMT_FLT) { // TODO: no need in this check? Not many of common formats support FLT // no conversion needed, direct copy from our frame to output buffer memcpy(output, _decodedFrame->data[0], inputPlaneSize); } else { int samplesWrittern = avresample_convert(_convertCtxAv, (uint8_t**) &output, outputPlaneSize, outputBufferSamples, (uint8_t**)_decodedFrame->data, inputPlaneSize, inputSamples); if (samplesWrittern < inputSamples) { // TODO: there may be data remaining in the internal FIFO buffer // to get this data: call avresample_convert() with NULL input // Test if this happens in practice ostringstream msg; msg << "AudioLoader: Incomplete format conversion (some samples missing)" << " from " << av_get_sample_fmt_name(_audioCtx->sample_fmt) << " to " << av_get_sample_fmt_name(AV_SAMPLE_FMT_FLT); throw EssentiaException(msg); } } *outputSize = outputPlaneSize; } else { E_DEBUG(EAlgorithm, "AudioLoader: tried to decode packet but didn't get any frame..."); *outputSize = 0; } return len; }
static int filter_frame(AVFilterLink *inlink, AVFrame *buf) { AVFilterContext *ctx = inlink->dst; ASyncContext *s = ctx->priv; AVFilterLink *outlink = ctx->outputs[0]; int nb_channels = av_get_channel_layout_nb_channels(buf->channel_layout); int64_t pts = (buf->pts == AV_NOPTS_VALUE) ? buf->pts : av_rescale_q(buf->pts, inlink->time_base, outlink->time_base); int out_size, ret; int64_t delta; int64_t new_pts; /* buffer data until we get the next timestamp */ if (s->pts == AV_NOPTS_VALUE || pts == AV_NOPTS_VALUE) { if (pts != AV_NOPTS_VALUE) { s->pts = pts - get_delay(s); } return write_to_fifo(s, buf); } if (s->first_pts != AV_NOPTS_VALUE) { handle_trimming(ctx); if (!avresample_available(s->avr)) return write_to_fifo(s, buf); } /* when we have two timestamps, compute how many samples would we have * to add/remove to get proper sync between data and timestamps */ delta = pts - s->pts - get_delay(s); out_size = avresample_available(s->avr); if (llabs(delta) > s->min_delta || (s->first_frame && delta && s->first_pts != AV_NOPTS_VALUE)) { av_log(ctx, AV_LOG_VERBOSE, "Discontinuity - %"PRId64" samples.\n", delta); out_size = av_clipl_int32((int64_t)out_size + delta); } else { if (s->resample) { // adjust the compensation if delta is non-zero int delay = get_delay(s); int comp = s->comp + av_clip(delta * inlink->sample_rate / delay, -s->max_comp, s->max_comp); if (comp != s->comp) { av_log(ctx, AV_LOG_VERBOSE, "Compensating %d samples per second.\n", comp); if (avresample_set_compensation(s->avr, comp, inlink->sample_rate) == 0) { s->comp = comp; } } } // adjust PTS to avoid monotonicity errors with input PTS jitter pts -= delta; delta = 0; } if (out_size > 0) { AVFrame *buf_out = ff_get_audio_buffer(outlink, out_size); if (!buf_out) { ret = AVERROR(ENOMEM); goto fail; } if (s->first_frame && delta > 0) { int planar = av_sample_fmt_is_planar(buf_out->format); int planes = planar ? nb_channels : 1; int block_size = av_get_bytes_per_sample(buf_out->format) * (planar ? 1 : nb_channels); int ch; av_samples_set_silence(buf_out->extended_data, 0, delta, nb_channels, buf->format); for (ch = 0; ch < planes; ch++) buf_out->extended_data[ch] += delta * block_size; avresample_read(s->avr, buf_out->extended_data, out_size); for (ch = 0; ch < planes; ch++) buf_out->extended_data[ch] -= delta * block_size; } else { avresample_read(s->avr, buf_out->extended_data, out_size); if (delta > 0) { av_samples_set_silence(buf_out->extended_data, out_size - delta, delta, nb_channels, buf->format); } } buf_out->pts = s->pts; ret = ff_filter_frame(outlink, buf_out); if (ret < 0) goto fail; s->got_output = 1; } else if (avresample_available(s->avr)) { av_log(ctx, AV_LOG_WARNING, "Non-monotonous timestamps, dropping " "whole buffer.\n"); } /* drain any remaining buffered data */ avresample_read(s->avr, NULL, avresample_available(s->avr)); new_pts = pts - avresample_get_delay(s->avr); /* check for s->pts monotonicity */ if (new_pts > s->pts) { s->pts = new_pts; ret = avresample_convert(s->avr, NULL, 0, 0, buf->extended_data, buf->linesize[0], buf->nb_samples); } else { av_log(ctx, AV_LOG_WARNING, "Non-monotonous timestamps, dropping " "whole buffer.\n"); ret = 0; } s->first_frame = 0; fail: av_frame_free(&buf); return ret; }
size_t getSampleOffset() { ssize_t clock_delay = (mFrameSize-mFramePos) / av_get_channel_layout_nb_channels(mOutputChannelLayout) / av_get_bytes_per_sample(mOutputSampleFormat); return (size_t)(mAudioClock*mAudioContext->sample_rate) - clock_delay; }
ResampleContext *swri_resample_init(ResampleContext *c, int out_rate, int in_rate, int filter_size, int phase_shift, int linear, double cutoff, enum AVSampleFormat format, enum SwrFilterType filter_type, int kaiser_beta){ double factor= FFMIN(out_rate * cutoff / in_rate, 1.0); int phase_count= 1<<phase_shift; if (!c || c->phase_shift != phase_shift || c->linear!=linear || c->factor != factor || c->filter_length != FFMAX((int)ceil(filter_size/factor), 1) || c->format != format || c->filter_type != filter_type || c->kaiser_beta != kaiser_beta) { c = av_mallocz(sizeof(*c)); if (!c) return NULL; c->format= format; c->felem_size= av_get_bytes_per_sample(c->format); switch(c->format){ case AV_SAMPLE_FMT_S16P: c->filter_shift = 15; break; case AV_SAMPLE_FMT_S32P: c->filter_shift = 30; break; case AV_SAMPLE_FMT_FLTP: case AV_SAMPLE_FMT_DBLP: c->filter_shift = 0; break; default: av_log(NULL, AV_LOG_ERROR, "Unsupported sample format\n"); return NULL; } c->phase_shift = phase_shift; c->phase_mask = phase_count - 1; c->linear = linear; c->factor = factor; c->filter_length = FFMAX((int)ceil(filter_size/factor), 1); c->filter_alloc = FFALIGN(c->filter_length, 8); c->filter_bank = av_mallocz(c->filter_alloc*(phase_count+1)*c->felem_size); c->filter_type = filter_type; c->kaiser_beta = kaiser_beta; if (!c->filter_bank) goto error; if (build_filter(c, (void*)c->filter_bank, factor, c->filter_length, c->filter_alloc, phase_count, 1<<c->filter_shift, filter_type, kaiser_beta)) goto error; memcpy(c->filter_bank + (c->filter_alloc*phase_count+1)*c->felem_size, c->filter_bank, (c->filter_alloc-1)*c->felem_size); memcpy(c->filter_bank + (c->filter_alloc*phase_count )*c->felem_size, c->filter_bank + (c->filter_alloc - 1)*c->felem_size, c->felem_size); } c->compensation_distance= 0; if(!av_reduce(&c->src_incr, &c->dst_incr, out_rate, in_rate * (int64_t)phase_count, INT32_MAX/2)) goto error; c->ideal_dst_incr= c->dst_incr; c->index= -phase_count*((c->filter_length-1)/2); c->frac= 0; return c; error: av_free(c->filter_bank); av_free(c); return NULL; }
int decode_audio_file(ChromaprintContext *chromaprint_ctx, int16_t *buffer1, int16_t *buffer2, const char *file_name, int max_length, int *duration) { int i, ok = 0, remaining, length, consumed, buffer_size, codec_ctx_opened = 0; AVFormatContext *format_ctx = NULL; AVCodecContext *codec_ctx = NULL; AVCodec *codec = NULL; AVStream *stream = NULL; AVPacket packet, packet_temp; #ifdef HAVE_AV_AUDIO_CONVERT AVAudioConvert *convert_ctx = NULL; #endif int16_t *buffer; if (!strcmp(file_name, "-")) { file_name = "pipe:0"; } #if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(53, 2, 0) if (av_open_input_file(&format_ctx, file_name, NULL, 0, NULL) != 0) { #else if (avformat_open_input(&format_ctx, file_name, NULL, NULL) != 0) { #endif fprintf(stderr, "ERROR: couldn't open the file\n"); goto done; } if (av_find_stream_info(format_ctx) < 0) { fprintf(stderr, "ERROR: couldn't find stream information in the file\n"); goto done; } for (i = 0; i < format_ctx->nb_streams; i++) { codec_ctx = format_ctx->streams[i]->codec; if (codec_ctx && codec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) { stream = format_ctx->streams[i]; break; } } if (!stream) { fprintf(stderr, "ERROR: couldn't find any audio stream in the file\n"); goto done; } codec = avcodec_find_decoder(codec_ctx->codec_id); if (!codec) { fprintf(stderr, "ERROR: unknown codec\n"); goto done; } if (avcodec_open(codec_ctx, codec) < 0) { fprintf(stderr, "ERROR: couldn't open the codec\n"); goto done; } codec_ctx_opened = 1; if (codec_ctx->channels <= 0) { fprintf(stderr, "ERROR: no channels found in the audio stream\n"); goto done; } if (codec_ctx->sample_fmt != AV_SAMPLE_FMT_S16) { #ifdef HAVE_AV_AUDIO_CONVERT convert_ctx = av_audio_convert_alloc(AV_SAMPLE_FMT_S16, codec_ctx->channels, codec_ctx->sample_fmt, codec_ctx->channels, NULL, 0); if (!convert_ctx) { fprintf(stderr, "ERROR: couldn't create sample format converter\n"); goto done; } #else fprintf(stderr, "ERROR: unsupported sample format\n"); goto done; #endif } *duration = stream->time_base.num * stream->duration / stream->time_base.den; av_init_packet(&packet); av_init_packet(&packet_temp); remaining = max_length * codec_ctx->channels * codec_ctx->sample_rate; chromaprint_start(chromaprint_ctx, codec_ctx->sample_rate, codec_ctx->channels); while (1) { if (av_read_frame(format_ctx, &packet) < 0) { break; } packet_temp.data = packet.data; packet_temp.size = packet.size; while (packet_temp.size > 0) { buffer_size = BUFFER_SIZE; #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(52, 23, 0) consumed = avcodec_decode_audio2(codec_ctx, buffer1, &buffer_size, packet_temp.data, packet_temp.size); #else consumed = avcodec_decode_audio3(codec_ctx, buffer1, &buffer_size, &packet_temp); #endif if (consumed < 0) { break; } packet_temp.data += consumed; packet_temp.size -= consumed; if (buffer_size <= 0) { if (buffer_size < 0) { fprintf(stderr, "WARNING: size returned from avcodec_decode_audioX is too small\n"); } continue; } if (buffer_size > BUFFER_SIZE) { fprintf(stderr, "WARNING: size returned from avcodec_decode_audioX is too large\n"); continue; } #ifdef HAVE_AV_AUDIO_CONVERT if (convert_ctx) { const void *ibuf[6] = { buffer1 }; void *obuf[6] = { buffer2 }; #if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(51, 8, 0) int istride[6] = { av_get_bits_per_sample_format(codec_ctx->sample_fmt) / 8 }; #else int istride[6] = { av_get_bytes_per_sample(codec_ctx->sample_fmt) }; #endif int ostride[6] = { 2 }; int len = buffer_size / istride[0]; if (av_audio_convert(convert_ctx, obuf, ostride, ibuf, istride, len) < 0) { break; } buffer = buffer2; buffer_size = len * ostride[0]; } else { buffer = buffer1; } #else buffer = buffer1; #endif length = MIN(remaining, buffer_size / 2); if (!chromaprint_feed(chromaprint_ctx, buffer, length)) { fprintf(stderr, "ERROR: fingerprint calculation failed\n"); goto done; } if (max_length) { remaining -= length; if (remaining <= 0) { goto finish; } } } if (packet.data) { av_free_packet(&packet); } } finish: if (!chromaprint_finish(chromaprint_ctx)) { fprintf(stderr, "ERROR: fingerprint calculation failed\n"); goto done; } ok = 1; done: if (codec_ctx_opened) { avcodec_close(codec_ctx); } if (format_ctx) { av_close_input_file(format_ctx); } #ifdef HAVE_AV_AUDIO_CONVERT if (convert_ctx) { av_audio_convert_free(convert_ctx); } #endif return ok; } int fpcalc_main(int argc, char **argv) { int i, j, max_length = 120, num_file_names = 0, raw = 0, raw_fingerprint_size, duration; int16_t *buffer1, *buffer2; int32_t *raw_fingerprint; char *file_name, *fingerprint, **file_names; ChromaprintContext *chromaprint_ctx; int algo = CHROMAPRINT_ALGORITHM_DEFAULT; file_names = malloc(argc * sizeof(char *)); for (i = 1; i < argc; i++) { char *arg = argv[i]; if (!strcmp(arg, "-length") && i + 1 < argc) { max_length = atoi(argv[++i]); } else if (!strcmp(arg, "-version") || !strcmp(arg, "-v")) { printf("fpcalc version %s\n", chromaprint_get_version()); return 0; } else if (!strcmp(arg, "-raw")) { raw = 1; } else if (!strcmp(arg, "-algo") && i + 1 < argc) { const char *v = argv[++i]; if (!strcmp(v, "test1")) { algo = CHROMAPRINT_ALGORITHM_TEST1; } else if (!strcmp(v, "test2")) { algo = CHROMAPRINT_ALGORITHM_TEST2; } else if (!strcmp(v, "test3")) { algo = CHROMAPRINT_ALGORITHM_TEST3; } else if (!strcmp(v, "test4")) { algo = CHROMAPRINT_ALGORITHM_TEST4; } else { fprintf(stderr, "WARNING: unknown algorithm, using the default\n"); } } else if (!strcmp(arg, "-set") && i + 1 < argc) { i += 1; } else { file_names[num_file_names++] = argv[i]; } } if (!num_file_names) { printf("usage: %s [OPTIONS] FILE...\n\n", argv[0]); printf("Options:\n"); printf(" -version print version information\n"); printf(" -length SECS length of the audio data used for fingerprint calculation (default 120)\n"); printf(" -raw output the raw uncompressed fingerprint\n"); printf(" -algo NAME version of the fingerprint algorithm\n"); return 2; } av_register_all(); av_log_set_level(AV_LOG_ERROR); buffer1 = av_malloc(BUFFER_SIZE + 16); buffer2 = av_malloc(BUFFER_SIZE + 16); chromaprint_ctx = chromaprint_new(algo); for (i = 1; i < argc; i++) { char *arg = argv[i]; if (!strcmp(arg, "-set") && i + 1 < argc) { char *name = argv[++i]; char *value = strchr(name, '='); if (value) { *value++ = '\0'; chromaprint_set_option(chromaprint_ctx, name, atoi(value)); } } } for (i = 0; i < num_file_names; i++) { file_name = file_names[i]; if (!decode_audio_file(chromaprint_ctx, buffer1, buffer2, file_name, max_length, &duration)) { fprintf(stderr, "ERROR: unable to calculate fingerprint for file %s, skipping\n", file_name); continue; } if (i > 0) { printf("\n"); } printf("FILE=%s\n", file_name); printf("DURATION=%d\n", duration); if (raw) { if (!chromaprint_get_raw_fingerprint(chromaprint_ctx, (void **)&raw_fingerprint, &raw_fingerprint_size)) { fprintf(stderr, "ERROR: unable to calculate fingerprint for file %s, skipping\n", file_name); continue; } printf("FINGERPRINT="); for (j = 0; j < raw_fingerprint_size; j++) { printf("%d%s", raw_fingerprint[j], j + 1 < raw_fingerprint_size ? "," : ""); } printf("\n"); chromaprint_dealloc(raw_fingerprint); } else { if (!chromaprint_get_fingerprint(chromaprint_ctx, &fingerprint)) { fprintf(stderr, "ERROR: unable to calculate fingerprint for file %s, skipping\n", file_name); continue; } printf("FINGERPRINT=%s\n", fingerprint); chromaprint_dealloc(fingerprint); } } chromaprint_free(chromaprint_ctx); av_free(buffer1); av_free(buffer2); free(file_names); return 0; }
static int init_buffers(AVFilterLink *inlink, int nb_samples) { AConvertContext *aconvert = inlink->dst->priv; AVFilterLink * const outlink = inlink->dst->outputs[0]; int i, packed_stride = 0; const unsigned packing_conv = inlink->planar != outlink->planar && aconvert->out_nb_channels != 1, format_conv = inlink->format != outlink->format; int nb_channels = aconvert->out_nb_channels; uninit(inlink->dst); aconvert->max_nb_samples = nb_samples; if (aconvert->convert_chlayout) { /* allocate buffer for storing intermediary mixing samplesref */ uint8_t *data[8]; int linesize[8]; int nb_channels = av_get_channel_layout_nb_channels(outlink->channel_layout); if (av_samples_alloc(data, linesize, nb_channels, nb_samples, inlink->format, inlink->planar, 16) < 0) goto fail_no_mem; aconvert->mix_samplesref = avfilter_get_audio_buffer_ref_from_arrays(data, linesize, AV_PERM_WRITE, nb_samples, inlink->format, outlink->channel_layout, inlink->planar); if (!aconvert->mix_samplesref) goto fail_no_mem; } // if there's a format/packing conversion we need an audio_convert context if (format_conv || packing_conv) { aconvert->out_samplesref = avfilter_get_audio_buffer(outlink, AV_PERM_WRITE, nb_samples); if (!aconvert->out_samplesref) goto fail_no_mem; aconvert->in_strides [0] = av_get_bytes_per_sample(inlink ->format); aconvert->out_strides[0] = av_get_bytes_per_sample(outlink->format); aconvert->out_conv = aconvert->out_samplesref->data; if (aconvert->mix_samplesref) aconvert->in_conv = aconvert->mix_samplesref->data; if (packing_conv) { // packed -> planar if (outlink->planar == AVFILTER_PLANAR) { if (aconvert->mix_samplesref) aconvert->packed_data[0] = aconvert->mix_samplesref->data[0]; aconvert->in_conv = aconvert->packed_data; packed_stride = aconvert->in_strides[0]; aconvert->in_strides[0] *= nb_channels; // planar -> packed } else { aconvert->packed_data[0] = aconvert->out_samplesref->data[0]; aconvert->out_conv = aconvert->packed_data; packed_stride = aconvert->out_strides[0]; aconvert->out_strides[0] *= nb_channels; } } else if (outlink->planar == AVFILTER_PACKED) { /* If there's no packing conversion, and the stream is packed * then we treat the entire stream as one big channel */ nb_channels = 1; } for (i = 1; i < nb_channels; i++) { aconvert->packed_data[i] = aconvert->packed_data[i-1] + packed_stride; aconvert->in_strides[i] = aconvert->in_strides[0]; aconvert->out_strides[i] = aconvert->out_strides[0]; } aconvert->audioconvert_ctx = av_audio_convert_alloc(outlink->format, nb_channels, inlink->format, nb_channels, NULL, 0); if (!aconvert->audioconvert_ctx) goto fail_no_mem; } return 0; fail_no_mem: av_log(inlink->dst, AV_LOG_ERROR, "Could not allocate memory.\n"); return AVERROR(ENOMEM); }
/** * Prepare filter for processing audio data of given format, * sample rate and number of channels. */ static int yae_reset(ATempoContext *atempo, enum AVSampleFormat format, int sample_rate, int channels) { const int sample_size = av_get_bytes_per_sample(format); uint32_t nlevels = 0; uint32_t pot; int i; atempo->format = format; atempo->channels = channels; atempo->stride = sample_size * channels; // pick a segment window size: atempo->window = sample_rate / 24; // adjust window size to be a power-of-two integer: nlevels = av_log2(atempo->window); pot = 1 << nlevels; av_assert0(pot <= atempo->window); if (pot < atempo->window) { atempo->window = pot * 2; nlevels++; } // initialize audio fragment buffers: REALLOC_OR_FAIL(atempo->frag[0].data, atempo->window * atempo->stride); REALLOC_OR_FAIL(atempo->frag[1].data, atempo->window * atempo->stride); REALLOC_OR_FAIL(atempo->frag[0].xdat, atempo->window * sizeof(FFTComplex)); REALLOC_OR_FAIL(atempo->frag[1].xdat, atempo->window * sizeof(FFTComplex)); // initialize rDFT contexts: av_rdft_end(atempo->real_to_complex); atempo->real_to_complex = NULL; av_rdft_end(atempo->complex_to_real); atempo->complex_to_real = NULL; atempo->real_to_complex = av_rdft_init(nlevels + 1, DFT_R2C); if (!atempo->real_to_complex) { yae_release_buffers(atempo); return AVERROR(ENOMEM); } atempo->complex_to_real = av_rdft_init(nlevels + 1, IDFT_C2R); if (!atempo->complex_to_real) { yae_release_buffers(atempo); return AVERROR(ENOMEM); } REALLOC_OR_FAIL(atempo->correlation, atempo->window * sizeof(FFTComplex)); atempo->ring = atempo->window * 3; REALLOC_OR_FAIL(atempo->buffer, atempo->ring * atempo->stride); // initialize the Hann window function: REALLOC_OR_FAIL(atempo->hann, atempo->window * sizeof(float)); for (i = 0; i < atempo->window; i++) { double t = (double)i / (double)(atempo->window - 1); double h = 0.5 * (1.0 - cos(2.0 * M_PI * t)); atempo->hann[i] = (float)h; } yae_clear(atempo); return 0; }
int audio_decode(const char *filename, struct song *song) { // decode the track AVCodec *codec = NULL; AVCodecContext *c = NULL; AVFormatContext *pFormatCtx; //int8_t* sample_array; int i, d, e; int len; AVPacket avpkt; AVFrame *decoded_frame = NULL; int8_t *beginning; int got_frame; int audioStream; size_t index; av_register_all(); av_init_packet(&avpkt); pFormatCtx = avformat_alloc_context(); if(avformat_open_input(&pFormatCtx, filename, NULL, NULL) < 0) { printf("Couldn't open file: %s, %d\n", filename, errno); song->nSamples = 0; return 1; } if(avformat_find_stream_info(pFormatCtx, NULL) < 0) { printf("Couldn't find stream information\n"); song->nSamples = 0; return 1; } audioStream = av_find_best_stream(pFormatCtx, AVMEDIA_TYPE_AUDIO, -1, -1, &codec, 0); c = pFormatCtx->streams[audioStream]->codec; if (!codec) { printf("Codec not found!\n"); song->nSamples = 0; return 1; } if(avcodec_open2(c, codec, NULL) < 0) { printf("Could not open codec\n"); song->nSamples = 0; return 1; } song->sample_rate = c->sample_rate; song->duration = pFormatCtx->duration/AV_TIME_BASE; size = (((uint64_t)(pFormatCtx->duration)*(uint64_t)song->sample_rate)/(uint64_t)AV_TIME_BASE)*c->channels*av_get_bytes_per_sample(c->sample_fmt); song->nSamples = (((uint64_t)(pFormatCtx->duration)*(uint64_t)song->sample_rate)/(uint64_t)AV_TIME_BASE)*c->channels; song->sample_array = malloc(size); for(i = 0; i < song->nSamples; ++i) *(song->sample_array + i) = 0; beginning = song->sample_array; index = 0; song->planar = av_sample_fmt_is_planar(c->sample_fmt); song->nb_bytes_per_sample = av_get_bytes_per_sample(c->sample_fmt); song->channels = c->channels; song->artist = song->tracknumber = song->title = song->album = NULL; /* Get tags */ if(av_dict_get(pFormatCtx->metadata, "track", NULL, AV_DICT_IGNORE_SUFFIX) != NULL) { song->tracknumber = malloc(strlen(av_dict_get(pFormatCtx->metadata, "TRACK", NULL, AV_DICT_IGNORE_SUFFIX)->value) + 1); strcpy(song->tracknumber, av_dict_get(pFormatCtx->metadata, "TRACK", NULL, AV_DICT_IGNORE_SUFFIX)->value); song->tracknumber[strcspn(song->tracknumber, "/")] = '\0'; } else { song->tracknumber = malloc(1*sizeof(char)); strcpy(song->tracknumber, ""); } if(av_dict_get(pFormatCtx->metadata, "title", NULL, AV_DICT_IGNORE_SUFFIX) != NULL) { song->title = malloc(strlen(av_dict_get(pFormatCtx->metadata, "TITLE", NULL, AV_DICT_IGNORE_SUFFIX)->value) + 1); strcpy(song->title, av_dict_get(pFormatCtx->metadata, "TITLE", NULL, AV_DICT_IGNORE_SUFFIX)->value); } else { song->title = malloc(12*sizeof(char)); strcpy(song->title, "<no title>"); } if(av_dict_get(pFormatCtx->metadata, "ARTIST", NULL, AV_DICT_IGNORE_SUFFIX) != NULL) { song->artist= malloc(strlen(av_dict_get(pFormatCtx->metadata, "ARTIST", NULL, AV_DICT_IGNORE_SUFFIX)->value) + 1); strcpy(song->artist, av_dict_get(pFormatCtx->metadata, "ARTIST", NULL, AV_DICT_IGNORE_SUFFIX)->value); } else { song->artist= malloc(12*sizeof(char)); strcpy(song->artist, "<no artist>"); } if(av_dict_get(pFormatCtx->metadata, "ALBUM", NULL, AV_DICT_IGNORE_SUFFIX) != NULL) { song->album= malloc(strlen(av_dict_get(pFormatCtx->metadata, "ALBUM", NULL, AV_DICT_IGNORE_SUFFIX)->value) + 1); strcpy(song->album, av_dict_get(pFormatCtx->metadata, "ALBUM", NULL, AV_DICT_IGNORE_SUFFIX)->value); } else { song->album= malloc(11*sizeof(char)); strcpy(song->album, "<no album>"); } /* End of codec init */ while(av_read_frame(pFormatCtx, &avpkt) >= 0) { if(avpkt.stream_index == audioStream) { got_frame = 0; if(!decoded_frame) { if(!(decoded_frame = av_frame_alloc())) { printf("Could not allocate audio frame\n"); exit(1); } } else av_frame_unref(decoded_frame); len = avcodec_decode_audio4(c, decoded_frame, &got_frame, &avpkt); if(len < 0) { //printf("Error while decoding\n"); //exit(1); avpkt.size=0; } av_free_packet(&avpkt); /* interesting part: copying decoded data into a huge array */ /* flac has a different behaviour from mp3, hence the planar condition */ if(got_frame) { size_t data_size = av_samples_get_buffer_size(NULL, c->channels, decoded_frame->nb_samples, c->sample_fmt, 1); if(index*song->nb_bytes_per_sample + data_size > size) { beginning = realloc(beginning, (size+=data_size)); song->nSamples+=data_size/song->nb_bytes_per_sample; } int8_t *p = beginning+index*song->nb_bytes_per_sample; if(song->planar == 1) { for(i = 0; i < decoded_frame->nb_samples*song->nb_bytes_per_sample; i+=song->nb_bytes_per_sample) { for(e = 0; e < c->channels; ++e) for(d = 0; d < song->nb_bytes_per_sample; ++d) *(p++) = ((int8_t*)(decoded_frame->extended_data[e]))[i+d]; } index+=data_size/song->nb_bytes_per_sample; } else if(song->planar == 0) { memcpy(index*song->nb_bytes_per_sample+beginning, decoded_frame->extended_data[0], data_size); index+=data_size/song->nb_bytes_per_sample; } } } } /* cleaning memory */ avformat_close_input(&pFormatCtx); song->sample_array = beginning; // av_frame_free(&decoded_frame); // av_free_packet(&avpkt); return 0; }
virtual void cpu_task() override { while (true) { if (Emu.IsStopped() || is_closed) { break; } if (!job.pop(task, &is_closed)) { break; } switch (task.type) { case adecStartSeq: { // TODO: reset data cellAdec.warning("adecStartSeq:"); reader.addr = 0; reader.size = 0; reader.init = false; reader.has_ats = false; just_started = true; if (adecIsAtracX(type)) { ch_cfg = task.at3p.channel_config; ch_out = task.at3p.channels; frame_size = task.at3p.frame_size; sample_rate = task.at3p.sample_rate; use_ats_headers = task.at3p.ats_header == 1; } break; } case adecEndSeq: { // TODO: finalize cellAdec.warning("adecEndSeq:"); cbFunc(*this, id, CELL_ADEC_MSG_TYPE_SEQDONE, CELL_OK, cbArg); just_finished = true; break; } case adecDecodeAu: { int err = 0; reader.addr = task.au.addr; reader.size = task.au.size; reader.has_ats = use_ats_headers; //LOG_NOTICE(HLE, "Audio AU: size = 0x%x, pts = 0x%llx", task.au.size, task.au.pts); if (just_started) { first_pts = task.au.pts; last_pts = task.au.pts; if (adecIsAtracX(type)) last_pts -= 0x10000; // hack } struct AVPacketHolder : AVPacket { AVPacketHolder(u32 size) { av_init_packet(this); if (size) { data = (u8*)av_calloc(1, size + FF_INPUT_BUFFER_PADDING_SIZE); this->size = size + FF_INPUT_BUFFER_PADDING_SIZE; } else { data = NULL; size = 0; } } ~AVPacketHolder() { av_free(data); } } au(0); if (just_started && just_finished) { avcodec_flush_buffers(ctx); reader.init = true; // wrong just_finished = false; just_started = false; } else if (just_started) // deferred initialization { AVDictionary* opts = nullptr; av_dict_set(&opts, "probesize", "96", 0); err = avformat_open_input(&fmt, NULL, input_format, &opts); if (err || opts) { throw EXCEPTION("avformat_open_input() failed (err=0x%x, opts=%d)", err, opts ? 1 : 0); } //err = avformat_find_stream_info(fmt, NULL); //if (err || !fmt->nb_streams) //{ // ADEC_ERROR("adecDecodeAu: avformat_find_stream_info() failed (err=0x%x, nb_streams=%d)", err, fmt->nb_streams); //} if (!avformat_new_stream(fmt, codec)) { throw EXCEPTION("avformat_new_stream() failed"); } ctx = fmt->streams[0]->codec; // TODO: check data opts = nullptr; av_dict_set(&opts, "refcounted_frames", "1", 0); { std::lock_guard<std::mutex> lock(g_mutex_avcodec_open2); // not multithread-safe (???) err = avcodec_open2(ctx, codec, &opts); } if (err || opts) { throw EXCEPTION("avcodec_open2() failed (err=0x%x, opts=%d)", err, opts ? 1 : 0); } just_started = false; } bool last_frame = false; while (true) { if (Emu.IsStopped() || is_closed) { if (Emu.IsStopped()) cellAdec.warning("adecDecodeAu: aborted"); break; } last_frame = av_read_frame(fmt, &au) < 0; if (last_frame) { //break; av_free(au.data); au.data = NULL; au.size = 0; } struct AdecFrameHolder : AdecFrame { AdecFrameHolder() { data = av_frame_alloc(); } ~AdecFrameHolder() { if (data) { av_frame_unref(data); av_frame_free(&data); } } } frame; if (!frame.data) { throw EXCEPTION("av_frame_alloc() failed"); } int got_frame = 0; int decode = avcodec_decode_audio4(ctx, frame.data, &got_frame, &au); if (decode <= 0) { if (decode < 0) { cellAdec.error("adecDecodeAu: AU decoding error(0x%x)", decode); } if (!got_frame && reader.size == 0) break; } if (got_frame) { //u64 ts = av_frame_get_best_effort_timestamp(frame.data); //if (ts != AV_NOPTS_VALUE) //{ // frame.pts = ts/* - first_pts*/; // last_pts = frame.pts; //} last_pts += ((u64)frame.data->nb_samples) * 90000 / frame.data->sample_rate; frame.pts = last_pts; s32 nbps = av_get_bytes_per_sample((AVSampleFormat)frame.data->format); switch (frame.data->format) { case AV_SAMPLE_FMT_FLTP: break; case AV_SAMPLE_FMT_S16P: break; default: { throw EXCEPTION("Unsupported frame format(%d)", frame.data->format); } } frame.auAddr = task.au.addr; frame.auSize = task.au.size; frame.userdata = task.au.userdata; frame.size = frame.data->nb_samples * frame.data->channels * nbps; //LOG_NOTICE(HLE, "got audio frame (pts=0x%llx, nb_samples=%d, ch=%d, sample_rate=%d, nbps=%d)", //frame.pts, frame.data->nb_samples, frame.data->channels, frame.data->sample_rate, nbps); if (frames.push(frame, &is_closed)) { frame.data = nullptr; // to prevent destruction cbFunc(*this, id, CELL_ADEC_MSG_TYPE_PCMOUT, CELL_OK, cbArg); } } } cbFunc(*this, id, CELL_ADEC_MSG_TYPE_AUDONE, task.au.auInfo_addr, cbArg); break; } case adecClose: { break; } default: { throw EXCEPTION("Unknown task(%d)", (u32)task.type); } } } is_finished = true; }
int avresample_open(AVAudioResampleContext *avr) { int ret; /* set channel mixing parameters */ avr->in_channels = av_get_channel_layout_nb_channels(avr->in_channel_layout); if (avr->in_channels <= 0 || avr->in_channels > AVRESAMPLE_MAX_CHANNELS) { av_log(avr, AV_LOG_ERROR, "Invalid input channel layout: %"PRIu64"\n", avr->in_channel_layout); return AVERROR(EINVAL); } avr->out_channels = av_get_channel_layout_nb_channels(avr->out_channel_layout); if (avr->out_channels <= 0 || avr->out_channels > AVRESAMPLE_MAX_CHANNELS) { av_log(avr, AV_LOG_ERROR, "Invalid output channel layout: %"PRIu64"\n", avr->out_channel_layout); return AVERROR(EINVAL); } avr->resample_channels = FFMIN(avr->in_channels, avr->out_channels); avr->downmix_needed = avr->in_channels > avr->out_channels; avr->upmix_needed = avr->out_channels > avr->in_channels || (!avr->downmix_needed && (avr->am->matrix || avr->in_channel_layout != avr->out_channel_layout)); avr->mixing_needed = avr->downmix_needed || avr->upmix_needed; /* set resampling parameters */ avr->resample_needed = avr->in_sample_rate != avr->out_sample_rate || avr->force_resampling; /* select internal sample format if not specified by the user */ if (avr->internal_sample_fmt == AV_SAMPLE_FMT_NONE && (avr->mixing_needed || avr->resample_needed)) { enum AVSampleFormat in_fmt = av_get_planar_sample_fmt(avr->in_sample_fmt); enum AVSampleFormat out_fmt = av_get_planar_sample_fmt(avr->out_sample_fmt); int max_bps = FFMAX(av_get_bytes_per_sample(in_fmt), av_get_bytes_per_sample(out_fmt)); if (max_bps <= 2) { avr->internal_sample_fmt = AV_SAMPLE_FMT_S16P; } else if (avr->mixing_needed) { avr->internal_sample_fmt = AV_SAMPLE_FMT_FLTP; } else { if (max_bps <= 4) { if (in_fmt == AV_SAMPLE_FMT_S32P || out_fmt == AV_SAMPLE_FMT_S32P) { if (in_fmt == AV_SAMPLE_FMT_FLTP || out_fmt == AV_SAMPLE_FMT_FLTP) { /* if one is s32 and the other is flt, use dbl */ avr->internal_sample_fmt = AV_SAMPLE_FMT_DBLP; } else { /* if one is s32 and the other is s32, s16, or u8, use s32 */ avr->internal_sample_fmt = AV_SAMPLE_FMT_S32P; } } else { /* if one is flt and the other is flt, s16 or u8, use flt */ avr->internal_sample_fmt = AV_SAMPLE_FMT_FLTP; } } else { /* if either is dbl, use dbl */ avr->internal_sample_fmt = AV_SAMPLE_FMT_DBLP; } } av_log(avr, AV_LOG_DEBUG, "Using %s as internal sample format\n", av_get_sample_fmt_name(avr->internal_sample_fmt)); } /* set sample format conversion parameters */ if (avr->in_channels == 1) avr->in_sample_fmt = av_get_planar_sample_fmt(avr->in_sample_fmt); if (avr->out_channels == 1) avr->out_sample_fmt = av_get_planar_sample_fmt(avr->out_sample_fmt); avr->in_convert_needed = (avr->resample_needed || avr->mixing_needed) && avr->in_sample_fmt != avr->internal_sample_fmt; if (avr->resample_needed || avr->mixing_needed) avr->out_convert_needed = avr->internal_sample_fmt != avr->out_sample_fmt; else avr->out_convert_needed = avr->in_sample_fmt != avr->out_sample_fmt; /* allocate buffers */ if (avr->mixing_needed || avr->in_convert_needed) { avr->in_buffer = ff_audio_data_alloc(FFMAX(avr->in_channels, avr->out_channels), 0, avr->internal_sample_fmt, "in_buffer"); if (!avr->in_buffer) { ret = AVERROR(EINVAL); goto error; } } if (avr->resample_needed) { avr->resample_out_buffer = ff_audio_data_alloc(avr->out_channels, 0, avr->internal_sample_fmt, "resample_out_buffer"); if (!avr->resample_out_buffer) { ret = AVERROR(EINVAL); goto error; } } if (avr->out_convert_needed) { avr->out_buffer = ff_audio_data_alloc(avr->out_channels, 0, avr->out_sample_fmt, "out_buffer"); if (!avr->out_buffer) { ret = AVERROR(EINVAL); goto error; } } avr->out_fifo = av_audio_fifo_alloc(avr->out_sample_fmt, avr->out_channels, 1024); if (!avr->out_fifo) { ret = AVERROR(ENOMEM); goto error; } /* setup contexts */ if (avr->in_convert_needed) { avr->ac_in = ff_audio_convert_alloc(avr, avr->internal_sample_fmt, avr->in_sample_fmt, avr->in_channels); if (!avr->ac_in) { ret = AVERROR(ENOMEM); goto error; } } if (avr->out_convert_needed) { enum AVSampleFormat src_fmt; if (avr->in_convert_needed) src_fmt = avr->internal_sample_fmt; else src_fmt = avr->in_sample_fmt; avr->ac_out = ff_audio_convert_alloc(avr, avr->out_sample_fmt, src_fmt, avr->out_channels); if (!avr->ac_out) { ret = AVERROR(ENOMEM); goto error; } } if (avr->resample_needed) { avr->resample = ff_audio_resample_init(avr); if (!avr->resample) { ret = AVERROR(ENOMEM); goto error; } } if (avr->mixing_needed) { ret = ff_audio_mix_init(avr); if (ret < 0) goto error; } return 0; error: avresample_close(avr); return ret; }
void _ffmpegPostAudioFrame(struct mAVStream* stream, int16_t left, int16_t right) { struct FFmpegEncoder* encoder = (struct FFmpegEncoder*) stream; if (!encoder->context || !encoder->audioCodec) { return; } if (encoder->absf && !left) { // XXX: AVBSF doesn't like silence. Figure out why. left = 1; } encoder->audioBuffer[encoder->currentAudioSample * 2] = left; encoder->audioBuffer[encoder->currentAudioSample * 2 + 1] = right; ++encoder->currentAudioSample; if (encoder->currentAudioSample * 4 < encoder->audioBufferSize) { return; } int channelSize = 2 * av_get_bytes_per_sample(encoder->audio->sample_fmt); encoder->currentAudioSample = 0; #ifdef USE_LIBAVRESAMPLE avresample_convert(encoder->resampleContext, 0, 0, 0, (uint8_t**) &encoder->audioBuffer, 0, encoder->audioBufferSize / 4); if (avresample_available(encoder->resampleContext) < encoder->audioFrame->nb_samples) { return; } #if LIBAVCODEC_VERSION_MAJOR >= 55 av_frame_make_writable(encoder->audioFrame); #endif int samples = avresample_read(encoder->resampleContext, encoder->audioFrame->data, encoder->postaudioBufferSize / channelSize); #else #if LIBAVCODEC_VERSION_MAJOR >= 55 av_frame_make_writable(encoder->audioFrame); #endif if (swr_get_out_samples(encoder->resampleContext, encoder->audioBufferSize / 4) < encoder->audioFrame->nb_samples) { swr_convert(encoder->resampleContext, NULL, 0, (const uint8_t**) &encoder->audioBuffer, encoder->audioBufferSize / 4); return; } int samples = swr_convert(encoder->resampleContext, encoder->audioFrame->data, encoder->postaudioBufferSize / channelSize, (const uint8_t**) &encoder->audioBuffer, encoder->audioBufferSize / 4); #endif encoder->audioFrame->pts = av_rescale_q(encoder->currentAudioFrame, encoder->audio->time_base, encoder->audioStream->time_base); encoder->currentAudioFrame += samples; AVPacket packet; av_init_packet(&packet); packet.data = 0; packet.size = 0; packet.pts = encoder->audioFrame->pts; int gotData; #ifdef FFMPEG_USE_PACKETS avcodec_send_frame(encoder->audio, encoder->audioFrame); gotData = avcodec_receive_packet(encoder->audio, &packet); gotData = (gotData == 0) && packet.size; #else avcodec_encode_audio2(encoder->audio, &packet, encoder->audioFrame, &gotData); #endif if (gotData) { if (encoder->absf) { AVPacket tempPacket; #ifdef FFMPEG_USE_NEW_BSF int success = av_bsf_send_packet(encoder->absf, &packet); if (success >= 0) { success = av_bsf_receive_packet(encoder->absf, &tempPacket); } #else int success = av_bitstream_filter_filter(encoder->absf, encoder->audio, 0, &tempPacket.data, &tempPacket.size, packet.data, packet.size, 0); #endif if (success >= 0) { #if LIBAVUTIL_VERSION_MAJOR >= 53 tempPacket.buf = av_buffer_create(tempPacket.data, tempPacket.size, av_buffer_default_free, 0, 0); #endif #ifdef FFMPEG_USE_PACKET_UNREF av_packet_move_ref(&packet, &tempPacket); #else av_free_packet(&packet); packet = tempPacket; #endif packet.stream_index = encoder->audioStream->index; av_interleaved_write_frame(encoder->context, &packet); } } else { packet.stream_index = encoder->audioStream->index; av_interleaved_write_frame(encoder->context, &packet); } } #ifdef FFMPEG_USE_PACKET_UNREF av_packet_unref(&packet); #else av_free_packet(&packet); #endif }
av_cold int swr_init(struct SwrContext *s){ int ret; char l1[1024], l2[1024]; clear_context(s); if(s-> in_sample_fmt >= AV_SAMPLE_FMT_NB){ av_log(s, AV_LOG_ERROR, "Requested input sample format %d is invalid\n", s->in_sample_fmt); return AVERROR(EINVAL); } if(s->out_sample_fmt >= AV_SAMPLE_FMT_NB){ av_log(s, AV_LOG_ERROR, "Requested output sample format %d is invalid\n", s->out_sample_fmt); return AVERROR(EINVAL); } s->out.ch_count = s-> user_out_ch_count; s-> in.ch_count = s-> user_in_ch_count; s->used_ch_count = s->user_used_ch_count; s-> in_ch_layout = s-> user_in_ch_layout; s->out_ch_layout = s->user_out_ch_layout; s->int_sample_fmt= s->user_int_sample_fmt; if(av_get_channel_layout_nb_channels(s-> in_ch_layout) > SWR_CH_MAX) { av_log(s, AV_LOG_WARNING, "Input channel layout 0x%"PRIx64" is invalid or unsupported.\n", s-> in_ch_layout); s->in_ch_layout = 0; } if(av_get_channel_layout_nb_channels(s->out_ch_layout) > SWR_CH_MAX) { av_log(s, AV_LOG_WARNING, "Output channel layout 0x%"PRIx64" is invalid or unsupported.\n", s->out_ch_layout); s->out_ch_layout = 0; } switch(s->engine){ #if CONFIG_LIBSOXR case SWR_ENGINE_SOXR: s->resampler = &swri_soxr_resampler; break; #endif case SWR_ENGINE_SWR : s->resampler = &swri_resampler; break; default: av_log(s, AV_LOG_ERROR, "Requested resampling engine is unavailable\n"); return AVERROR(EINVAL); } if(!s->used_ch_count) s->used_ch_count= s->in.ch_count; if(s->used_ch_count && s-> in_ch_layout && s->used_ch_count != av_get_channel_layout_nb_channels(s-> in_ch_layout)){ av_log(s, AV_LOG_WARNING, "Input channel layout has a different number of channels than the number of used channels, ignoring layout\n"); s-> in_ch_layout= 0; } if(!s-> in_ch_layout) s-> in_ch_layout= av_get_default_channel_layout(s->used_ch_count); if(!s->out_ch_layout) s->out_ch_layout= av_get_default_channel_layout(s->out.ch_count); s->rematrix= s->out_ch_layout !=s->in_ch_layout || s->rematrix_volume!=1.0 || s->rematrix_custom; if(s->int_sample_fmt == AV_SAMPLE_FMT_NONE){ if( av_get_bytes_per_sample(s-> in_sample_fmt) <= 2 && av_get_bytes_per_sample(s->out_sample_fmt) <= 2){ s->int_sample_fmt= AV_SAMPLE_FMT_S16P; }else if( av_get_bytes_per_sample(s-> in_sample_fmt) <= 2 && !s->rematrix && s->out_sample_rate==s->in_sample_rate && !(s->flags & SWR_FLAG_RESAMPLE)){ s->int_sample_fmt= AV_SAMPLE_FMT_S16P; }else if( av_get_planar_sample_fmt(s-> in_sample_fmt) == AV_SAMPLE_FMT_S32P && av_get_planar_sample_fmt(s->out_sample_fmt) == AV_SAMPLE_FMT_S32P && !s->rematrix && s->engine != SWR_ENGINE_SOXR){ s->int_sample_fmt= AV_SAMPLE_FMT_S32P; }else if(av_get_bytes_per_sample(s->in_sample_fmt) <= 4){ s->int_sample_fmt= AV_SAMPLE_FMT_FLTP; }else{ s->int_sample_fmt= AV_SAMPLE_FMT_DBLP; } } av_log(s, AV_LOG_DEBUG, "Using %s internally between filters\n", av_get_sample_fmt_name(s->int_sample_fmt)); if( s->int_sample_fmt != AV_SAMPLE_FMT_S16P &&s->int_sample_fmt != AV_SAMPLE_FMT_S32P &&s->int_sample_fmt != AV_SAMPLE_FMT_FLTP &&s->int_sample_fmt != AV_SAMPLE_FMT_DBLP){ av_log(s, AV_LOG_ERROR, "Requested sample format %s is not supported internally, S16/S32/FLT/DBL is supported\n", av_get_sample_fmt_name(s->int_sample_fmt)); return AVERROR(EINVAL); } set_audiodata_fmt(&s-> in, s-> in_sample_fmt); set_audiodata_fmt(&s->out, s->out_sample_fmt); if (s->firstpts_in_samples != AV_NOPTS_VALUE) { if (!s->async && s->min_compensation >= FLT_MAX/2) s->async = 1; s->firstpts = s->outpts = s->firstpts_in_samples * s->out_sample_rate; } else s->firstpts = AV_NOPTS_VALUE; if (s->async) { if (s->min_compensation >= FLT_MAX/2) s->min_compensation = 0.001; if (s->async > 1.0001) { s->max_soft_compensation = s->async / (double) s->in_sample_rate; } } if (s->out_sample_rate!=s->in_sample_rate || (s->flags & SWR_FLAG_RESAMPLE)){ s->resample = s->resampler->init(s->resample, s->out_sample_rate, s->in_sample_rate, s->filter_size, s->phase_shift, s->linear_interp, s->cutoff, s->int_sample_fmt, s->filter_type, s->kaiser_beta, s->precision, s->cheby); if (!s->resample) { av_log(s, AV_LOG_ERROR, "Failed to initialize resampler\n"); return AVERROR(ENOMEM); } }else s->resampler->free(&s->resample); if( s->int_sample_fmt != AV_SAMPLE_FMT_S16P && s->int_sample_fmt != AV_SAMPLE_FMT_S32P && s->int_sample_fmt != AV_SAMPLE_FMT_FLTP && s->int_sample_fmt != AV_SAMPLE_FMT_DBLP && s->resample){ av_log(s, AV_LOG_ERROR, "Resampling only supported with internal s16/s32/flt/dbl\n"); ret = AVERROR(EINVAL); goto fail; } #define RSC 1 //FIXME finetune if(!s-> in.ch_count) s-> in.ch_count= av_get_channel_layout_nb_channels(s-> in_ch_layout); if(!s->used_ch_count) s->used_ch_count= s->in.ch_count; if(!s->out.ch_count) s->out.ch_count= av_get_channel_layout_nb_channels(s->out_ch_layout); if(!s-> in.ch_count){ av_assert0(!s->in_ch_layout); av_log(s, AV_LOG_ERROR, "Input channel count and layout are unset\n"); ret = AVERROR(EINVAL); goto fail; } av_get_channel_layout_string(l1, sizeof(l1), s-> in.ch_count, s-> in_ch_layout); av_get_channel_layout_string(l2, sizeof(l2), s->out.ch_count, s->out_ch_layout); if (s->out_ch_layout && s->out.ch_count != av_get_channel_layout_nb_channels(s->out_ch_layout)) { av_log(s, AV_LOG_ERROR, "Output channel layout %s mismatches specified channel count %d\n", l2, s->out.ch_count); ret = AVERROR(EINVAL); goto fail; } if (s->in_ch_layout && s->used_ch_count != av_get_channel_layout_nb_channels(s->in_ch_layout)) { av_log(s, AV_LOG_ERROR, "Input channel layout %s mismatches specified channel count %d\n", l1, s->used_ch_count); ret = AVERROR(EINVAL); goto fail; } if ((!s->out_ch_layout || !s->in_ch_layout) && s->used_ch_count != s->out.ch_count && !s->rematrix_custom) { av_log(s, AV_LOG_ERROR, "Rematrix is needed between %s and %s " "but there is not enough information to do it\n", l1, l2); ret = AVERROR(EINVAL); goto fail; } av_assert0(s->used_ch_count); av_assert0(s->out.ch_count); s->resample_first= RSC*s->out.ch_count/s->in.ch_count - RSC < s->out_sample_rate/(float)s-> in_sample_rate - 1.0; s->in_buffer= s->in; s->silence = s->in; s->drop_temp= s->out; if(!s->resample && !s->rematrix && !s->channel_map && !s->dither.method){ s->full_convert = swri_audio_convert_alloc(s->out_sample_fmt, s-> in_sample_fmt, s-> in.ch_count, NULL, 0); return 0; } s->in_convert = swri_audio_convert_alloc(s->int_sample_fmt, s-> in_sample_fmt, s->used_ch_count, s->channel_map, 0); s->out_convert= swri_audio_convert_alloc(s->out_sample_fmt, s->int_sample_fmt, s->out.ch_count, NULL, 0); if (!s->in_convert || !s->out_convert) { ret = AVERROR(ENOMEM); goto fail; } s->postin= s->in; s->preout= s->out; s->midbuf= s->in; if(s->channel_map){ s->postin.ch_count= s->midbuf.ch_count= s->used_ch_count; if(s->resample) s->in_buffer.ch_count= s->used_ch_count; } if(!s->resample_first){ s->midbuf.ch_count= s->out.ch_count; if(s->resample) s->in_buffer.ch_count = s->out.ch_count; } set_audiodata_fmt(&s->postin, s->int_sample_fmt); set_audiodata_fmt(&s->midbuf, s->int_sample_fmt); set_audiodata_fmt(&s->preout, s->int_sample_fmt); if(s->resample){ set_audiodata_fmt(&s->in_buffer, s->int_sample_fmt); } if ((ret = swri_dither_init(s, s->out_sample_fmt, s->int_sample_fmt)) < 0) goto fail; if(s->rematrix || s->dither.method) { ret = swri_rematrix_init(s); if (ret < 0) goto fail; } return 0; fail: swr_close(s); return ret; }
hb_audio_resample_t* hb_audio_resample_init(enum AVSampleFormat sample_fmt, int hb_amixdown, int normalize_mix) { hb_audio_resample_t *resample = calloc(1, sizeof(hb_audio_resample_t)); if (resample == NULL) { hb_error("hb_audio_resample_init: failed to allocate resample"); goto fail; } // avresample context, initialized in hb_audio_resample_update() resample->avresample = NULL; // we don't support planar output yet if (av_sample_fmt_is_planar(sample_fmt)) { hb_error("hb_audio_resample_init: planar output not supported ('%s')", av_get_sample_fmt_name(sample_fmt)); goto fail; } // convert mixdown to channel_layout/matrix_encoding combo int matrix_encoding; uint64_t channel_layout = hb_ff_mixdown_xlat(hb_amixdown, &matrix_encoding); /* * When downmixing, Dual Mono to Mono is a special case: * the audio must remain 2-channel until all conversions are done. */ if (hb_amixdown == HB_AMIXDOWN_LEFT || hb_amixdown == HB_AMIXDOWN_RIGHT) { channel_layout = AV_CH_LAYOUT_STEREO; resample->dual_mono_downmix = 1; resample->dual_mono_right_only = (hb_amixdown == HB_AMIXDOWN_RIGHT); } else { resample->dual_mono_downmix = 0; } // requested output channel_layout, sample_fmt resample->out.channels = av_get_channel_layout_nb_channels(channel_layout); resample->out.channel_layout = channel_layout; resample->out.matrix_encoding = matrix_encoding; resample->out.normalize_mix_level = normalize_mix; resample->out.sample_fmt = sample_fmt; resample->out.sample_size = av_get_bytes_per_sample(sample_fmt); // set default input characteristics resample->in.sample_fmt = resample->out.sample_fmt; resample->in.channel_layout = resample->out.channel_layout; resample->in.center_mix_level = HB_MIXLEV_DEFAULT; resample->in.surround_mix_level = HB_MIXLEV_DEFAULT; // by default, no conversion needed resample->resample_needed = 0; return resample; fail: hb_audio_resample_free(resample); return NULL; }
int swr_init(struct SwrContext *s){ s->in_buffer_index= 0; s->in_buffer_count= 0; s->resample_in_constraint= 0; free_temp(&s->postin); free_temp(&s->midbuf); free_temp(&s->preout); free_temp(&s->in_buffer); swri_audio_convert_free(&s-> in_convert); swri_audio_convert_free(&s->out_convert); swri_audio_convert_free(&s->full_convert); s-> in.planar= av_sample_fmt_is_planar(s-> in_sample_fmt); s->out.planar= av_sample_fmt_is_planar(s->out_sample_fmt); s-> in_sample_fmt= av_get_alt_sample_fmt(s-> in_sample_fmt, 0); s->out_sample_fmt= av_get_alt_sample_fmt(s->out_sample_fmt, 0); if(s-> in_sample_fmt >= AV_SAMPLE_FMT_NB){ av_log(s, AV_LOG_ERROR, "Requested input sample format %d is invalid\n", s->in_sample_fmt); return AVERROR(EINVAL); } if(s->out_sample_fmt >= AV_SAMPLE_FMT_NB){ av_log(s, AV_LOG_ERROR, "Requested output sample format %d is invalid\n", s->out_sample_fmt); return AVERROR(EINVAL); } if( s->int_sample_fmt != AV_SAMPLE_FMT_S16 &&s->int_sample_fmt != AV_SAMPLE_FMT_FLT){ av_log(s, AV_LOG_ERROR, "Requested sample format %s is not supported internally, only float & S16 is supported\n", av_get_sample_fmt_name(s->int_sample_fmt)); return AVERROR(EINVAL); } //FIXME should we allow/support using FLT on material that doesnt need it ? if(s->in_sample_fmt <= AV_SAMPLE_FMT_S16 || s->int_sample_fmt==AV_SAMPLE_FMT_S16){ s->int_sample_fmt= AV_SAMPLE_FMT_S16; }else s->int_sample_fmt= AV_SAMPLE_FMT_FLT; if (s->out_sample_rate!=s->in_sample_rate || (s->flags & SWR_FLAG_RESAMPLE)){ s->resample = swri_resample_init(s->resample, s->out_sample_rate, s->in_sample_rate, 16, 10, 0, 0.8); }else swri_resample_free(&s->resample); if(s->int_sample_fmt != AV_SAMPLE_FMT_S16 && s->resample){ av_log(s, AV_LOG_ERROR, "Resampling only supported with internal s16 currently\n"); //FIXME return -1; } if(!s->used_ch_count) s->used_ch_count= s->in.ch_count; if(s->used_ch_count && s-> in_ch_layout && s->used_ch_count != av_get_channel_layout_nb_channels(s-> in_ch_layout)){ av_log(s, AV_LOG_WARNING, "Input channel layout has a different number of channels than the number of used channels, ignoring layout\n"); s-> in_ch_layout= 0; } if(!s-> in_ch_layout) s-> in_ch_layout= av_get_default_channel_layout(s->used_ch_count); if(!s->out_ch_layout) s->out_ch_layout= av_get_default_channel_layout(s->out.ch_count); s->rematrix= s->out_ch_layout !=s->in_ch_layout || s->rematrix_volume!=1.0; #define RSC 1 //FIXME finetune if(!s-> in.ch_count) s-> in.ch_count= av_get_channel_layout_nb_channels(s-> in_ch_layout); if(!s->used_ch_count) s->used_ch_count= s->in.ch_count; if(!s->out.ch_count) s->out.ch_count= av_get_channel_layout_nb_channels(s->out_ch_layout); if(!s-> in.ch_count){ av_assert0(!s->in_ch_layout); av_log(s, AV_LOG_ERROR, "Input channel count and layout are unset\n"); return -1; } av_assert0(s->used_ch_count); av_assert0(s->out.ch_count); s->resample_first= RSC*s->out.ch_count/s->in.ch_count - RSC < s->out_sample_rate/(float)s-> in_sample_rate - 1.0; s-> in.bps= av_get_bytes_per_sample(s-> in_sample_fmt); s->int_bps= av_get_bytes_per_sample(s->int_sample_fmt); s->out.bps= av_get_bytes_per_sample(s->out_sample_fmt); if(!s->resample && !s->rematrix && !s->channel_map){ s->full_convert = swri_audio_convert_alloc(s->out_sample_fmt, s-> in_sample_fmt, s-> in.ch_count, NULL, 0); return 0; } s->in_convert = swri_audio_convert_alloc(s->int_sample_fmt, s-> in_sample_fmt, s->used_ch_count, s->channel_map, 0); s->out_convert= swri_audio_convert_alloc(s->out_sample_fmt, s->int_sample_fmt, s->out.ch_count, NULL, 0); s->postin= s->in; s->preout= s->out; s->midbuf= s->in; s->in_buffer= s->in; if(s->channel_map){ s->postin.ch_count= s->midbuf.ch_count= s->in_buffer.ch_count= s->used_ch_count; } if(!s->resample_first){ s->midbuf.ch_count= s->out.ch_count; s->in_buffer.ch_count = s->out.ch_count; } s->in_buffer.bps = s->postin.bps = s->midbuf.bps = s->preout.bps = s->int_bps; s->in_buffer.planar = s->postin.planar = s->midbuf.planar = s->preout.planar = 1; if(s->rematrix) return swri_rematrix_init(s); return 0; }
int avresample_open(AVAudioResampleContext *avr) { int ret; if (avresample_is_open(avr)) { av_log(avr, AV_LOG_ERROR, "The resampling context is already open.\n"); return AVERROR(EINVAL); } /* set channel mixing parameters */ avr->in_channels = av_get_channel_layout_nb_channels(avr->in_channel_layout); if (avr->in_channels <= 0 || avr->in_channels > AVRESAMPLE_MAX_CHANNELS) { av_log(avr, AV_LOG_ERROR, "Invalid input channel layout: %"PRIu64"\n", avr->in_channel_layout); return AVERROR(EINVAL); } avr->out_channels = av_get_channel_layout_nb_channels(avr->out_channel_layout); if (avr->out_channels <= 0 || avr->out_channels > AVRESAMPLE_MAX_CHANNELS) { av_log(avr, AV_LOG_ERROR, "Invalid output channel layout: %"PRIu64"\n", avr->out_channel_layout); return AVERROR(EINVAL); } avr->resample_channels = FFMIN(avr->in_channels, avr->out_channels); avr->downmix_needed = avr->in_channels > avr->out_channels; avr->upmix_needed = avr->out_channels > avr->in_channels || (!avr->downmix_needed && (avr->mix_matrix || avr->in_channel_layout != avr->out_channel_layout)); avr->mixing_needed = avr->downmix_needed || avr->upmix_needed; /* set resampling parameters */ avr->resample_needed = avr->in_sample_rate != avr->out_sample_rate || avr->force_resampling; /* select internal sample format if not specified by the user */ if (avr->internal_sample_fmt == AV_SAMPLE_FMT_NONE && (avr->mixing_needed || avr->resample_needed)) { enum AVSampleFormat in_fmt = av_get_planar_sample_fmt(avr->in_sample_fmt); enum AVSampleFormat out_fmt = av_get_planar_sample_fmt(avr->out_sample_fmt); int max_bps = FFMAX(av_get_bytes_per_sample(in_fmt), av_get_bytes_per_sample(out_fmt)); if (max_bps <= 2) { avr->internal_sample_fmt = AV_SAMPLE_FMT_S16P; } else if (avr->mixing_needed) { avr->internal_sample_fmt = AV_SAMPLE_FMT_FLTP; } else { if (max_bps <= 4) { if (in_fmt == AV_SAMPLE_FMT_S32P || out_fmt == AV_SAMPLE_FMT_S32P) { if (in_fmt == AV_SAMPLE_FMT_FLTP || out_fmt == AV_SAMPLE_FMT_FLTP) { /* if one is s32 and the other is flt, use dbl */ avr->internal_sample_fmt = AV_SAMPLE_FMT_DBLP; } else { /* if one is s32 and the other is s32, s16, or u8, use s32 */ avr->internal_sample_fmt = AV_SAMPLE_FMT_S32P; } } else { /* if one is flt and the other is flt, s16 or u8, use flt */ avr->internal_sample_fmt = AV_SAMPLE_FMT_FLTP; } } else { /* if either is dbl, use dbl */ avr->internal_sample_fmt = AV_SAMPLE_FMT_DBLP; } } av_log(avr, AV_LOG_DEBUG, "Using %s as internal sample format\n", av_get_sample_fmt_name(avr->internal_sample_fmt)); } /* treat all mono as planar for easier comparison */ if (avr->in_channels == 1) avr->in_sample_fmt = av_get_planar_sample_fmt(avr->in_sample_fmt); if (avr->out_channels == 1) avr->out_sample_fmt = av_get_planar_sample_fmt(avr->out_sample_fmt); /* we may need to add an extra conversion in order to remap channels if the output format is not planar */ if (avr->use_channel_map && !avr->mixing_needed && !avr->resample_needed && !av_sample_fmt_is_planar(avr->out_sample_fmt)) { avr->internal_sample_fmt = av_get_planar_sample_fmt(avr->out_sample_fmt); } /* set sample format conversion parameters */ if (avr->resample_needed || avr->mixing_needed) avr->in_convert_needed = avr->in_sample_fmt != avr->internal_sample_fmt; else avr->in_convert_needed = avr->use_channel_map && !av_sample_fmt_is_planar(avr->out_sample_fmt); if (avr->resample_needed || avr->mixing_needed || avr->in_convert_needed) avr->out_convert_needed = avr->internal_sample_fmt != avr->out_sample_fmt; else avr->out_convert_needed = avr->in_sample_fmt != avr->out_sample_fmt; avr->in_copy_needed = !avr->in_convert_needed && (avr->mixing_needed || (avr->use_channel_map && avr->resample_needed)); if (avr->use_channel_map) { if (avr->in_copy_needed) { avr->remap_point = REMAP_IN_COPY; av_dlog(avr, "remap channels during in_copy\n"); } else if (avr->in_convert_needed) { avr->remap_point = REMAP_IN_CONVERT; av_dlog(avr, "remap channels during in_convert\n"); } else if (avr->out_convert_needed) { avr->remap_point = REMAP_OUT_CONVERT; av_dlog(avr, "remap channels during out_convert\n"); } else { avr->remap_point = REMAP_OUT_COPY; av_dlog(avr, "remap channels during out_copy\n"); } #ifdef DEBUG { int ch; av_dlog(avr, "output map: "); if (avr->ch_map_info.do_remap) for (ch = 0; ch < avr->in_channels; ch++) av_dlog(avr, " % 2d", avr->ch_map_info.channel_map[ch]); else av_dlog(avr, "n/a"); av_dlog(avr, "\n"); av_dlog(avr, "copy map: "); if (avr->ch_map_info.do_copy) for (ch = 0; ch < avr->in_channels; ch++) av_dlog(avr, " % 2d", avr->ch_map_info.channel_copy[ch]); else av_dlog(avr, "n/a"); av_dlog(avr, "\n"); av_dlog(avr, "zero map: "); if (avr->ch_map_info.do_zero) for (ch = 0; ch < avr->in_channels; ch++) av_dlog(avr, " % 2d", avr->ch_map_info.channel_zero[ch]); else av_dlog(avr, "n/a"); av_dlog(avr, "\n"); av_dlog(avr, "input map: "); for (ch = 0; ch < avr->in_channels; ch++) av_dlog(avr, " % 2d", avr->ch_map_info.input_map[ch]); av_dlog(avr, "\n"); } #endif } else avr->remap_point = REMAP_NONE; /* allocate buffers */ if (avr->in_copy_needed || avr->in_convert_needed) { avr->in_buffer = ff_audio_data_alloc(FFMAX(avr->in_channels, avr->out_channels), 0, avr->internal_sample_fmt, "in_buffer"); if (!avr->in_buffer) { ret = AVERROR(EINVAL); goto error; } } if (avr->resample_needed) { avr->resample_out_buffer = ff_audio_data_alloc(avr->out_channels, 1024, avr->internal_sample_fmt, "resample_out_buffer"); if (!avr->resample_out_buffer) { ret = AVERROR(EINVAL); goto error; } } if (avr->out_convert_needed) { avr->out_buffer = ff_audio_data_alloc(avr->out_channels, 0, avr->out_sample_fmt, "out_buffer"); if (!avr->out_buffer) { ret = AVERROR(EINVAL); goto error; } } avr->out_fifo = av_audio_fifo_alloc(avr->out_sample_fmt, avr->out_channels, 1024); if (!avr->out_fifo) { ret = AVERROR(ENOMEM); goto error; } /* setup contexts */ if (avr->in_convert_needed) { avr->ac_in = ff_audio_convert_alloc(avr, avr->internal_sample_fmt, avr->in_sample_fmt, avr->in_channels, avr->in_sample_rate, avr->remap_point == REMAP_IN_CONVERT); if (!avr->ac_in) { ret = AVERROR(ENOMEM); goto error; } } if (avr->out_convert_needed) { enum AVSampleFormat src_fmt; if (avr->in_convert_needed) src_fmt = avr->internal_sample_fmt; else src_fmt = avr->in_sample_fmt; avr->ac_out = ff_audio_convert_alloc(avr, avr->out_sample_fmt, src_fmt, avr->out_channels, avr->out_sample_rate, avr->remap_point == REMAP_OUT_CONVERT); if (!avr->ac_out) { ret = AVERROR(ENOMEM); goto error; } } if (avr->resample_needed) { avr->resample = ff_audio_resample_init(avr); if (!avr->resample) { ret = AVERROR(ENOMEM); goto error; } } if (avr->mixing_needed) { avr->am = ff_audio_mix_alloc(avr); if (!avr->am) { ret = AVERROR(ENOMEM); goto error; } } return 0; error: avresample_close(avr); return ret; }
int decode_audio(AVCodecContext *ctx, queue_t *qa) { static struct SwrContext *swr_ctx; static int64_t src_layout; static int src_freq; static int src_channels; static enum AVSampleFormat src_fmt = -1; static AVFrame *aFrame; AVPacket pkt; AVPacket pkt_tmp; int64_t dec_channel_layout; int len, len2; int got_frame; int data_size; if( astream.count > 192000*2) return -1; if( get_packet(qa, &pkt) == 0 ) return 0; // __asm__("int3"); if (!aFrame) { if (!(aFrame = avcodec_alloc_frame())) return -1; } else avcodec_get_frame_defaults(aFrame); pkt_tmp = pkt; while(pkt_tmp.size > 0) { data_size = 192000; // len = avcodec_decode_audio3(ctx,(int16_t*)decoder_buffer, // &data_size, &pkt_tmp); got_frame = 0; len = avcodec_decode_audio4(ctx, aFrame, &got_frame, &pkt_tmp); if(len >= 0 && got_frame) { char *samples; int ch, plane_size; int planar = av_sample_fmt_is_planar(ctx->sample_fmt); int data_size = av_samples_get_buffer_size(&plane_size, ctx->channels, aFrame->nb_samples, ctx->sample_fmt, 1); // if(audio_base == -1.0) // { // if (pkt.pts != AV_NOPTS_VALUE) // audio_base = get_audio_base() * pkt.pts; // printf("audio base %f\n", audio_base); // }; pkt_tmp.data += len; pkt_tmp.size -= len; dec_channel_layout = (aFrame->channel_layout && aFrame->channels == av_get_channel_layout_nb_channels(aFrame->channel_layout)) ? aFrame->channel_layout : av_get_default_channel_layout(aFrame->channels); if (aFrame->format != src_fmt || dec_channel_layout != src_layout || aFrame->sample_rate != src_freq || !swr_ctx) { swr_free(&swr_ctx); swr_ctx = swr_alloc_set_opts(NULL, AV_CH_LAYOUT_STEREO, AV_SAMPLE_FMT_S16, aFrame->sample_rate, dec_channel_layout,aFrame->format, aFrame->sample_rate, 0, NULL); if (!swr_ctx || swr_init(swr_ctx) < 0) { printf("Cannot create sample rate converter for conversion of %d Hz %s %d channels to %d Hz %s %d channels!\n", aFrame->sample_rate, av_get_sample_fmt_name(aFrame->format), (int)aFrame->channels, aFrame->sample_rate, av_get_sample_fmt_name(AV_SAMPLE_FMT_S16), 2); break; } src_layout = dec_channel_layout; src_channels = aFrame->channels; src_freq = aFrame->sample_rate; src_fmt = aFrame->format; }; if (swr_ctx) { const uint8_t **in = (const uint8_t **)aFrame->extended_data; uint8_t *out[] = {decoder_buffer}; int out_count = 192000 * 3 / 2 / av_get_bytes_per_sample(AV_SAMPLE_FMT_S16); len2 = swr_convert(swr_ctx, out, out_count, in, aFrame->nb_samples); if (len2 < 0) { printf("swr_convert() failed\n"); break; } if (len2 == out_count) { printf("warning: audio buffer is probably too small\n"); swr_init(swr_ctx); } data_size = len2 * 2 * av_get_bytes_per_sample(AV_SAMPLE_FMT_S16); mutex_lock(&astream.lock); samples = astream.buffer+astream.count; memcpy(samples, decoder_buffer, data_size); /* memcpy(samples, aFrame->extended_data[0], plane_size); if (planar && ctx->channels > 1) { uint8_t *out = ((uint8_t *)samples) + plane_size; for (ch = 1; ch < ctx->channels; ch++) { memcpy(out, aFrame->extended_data[ch], plane_size); out += plane_size; } } */ astream.count += data_size; mutex_unlock(&astream.lock); }; } else pkt_tmp.size = 0; } av_free_packet(&pkt); return 1; };
int swri_dither_init(SwrContext *s, enum AVSampleFormat out_fmt, enum AVSampleFormat in_fmt) { int i; double scale = 0; if (s->dither.method > SWR_DITHER_TRIANGULAR_HIGHPASS && s->dither.method <= SWR_DITHER_NS) return AVERROR(EINVAL); out_fmt = av_get_packed_sample_fmt(out_fmt); in_fmt = av_get_packed_sample_fmt( in_fmt); if(in_fmt == AV_SAMPLE_FMT_FLT || in_fmt == AV_SAMPLE_FMT_DBL){ if(out_fmt == AV_SAMPLE_FMT_S32) scale = 1.0/(1L<<31); if(out_fmt == AV_SAMPLE_FMT_S16) scale = 1.0/(1L<<15); if(out_fmt == AV_SAMPLE_FMT_U8 ) scale = 1.0/(1L<< 7); } if(in_fmt == AV_SAMPLE_FMT_S32 && out_fmt == AV_SAMPLE_FMT_S16) scale = 1L<<16; if(in_fmt == AV_SAMPLE_FMT_S32 && out_fmt == AV_SAMPLE_FMT_U8 ) scale = 1L<<24; if(in_fmt == AV_SAMPLE_FMT_S16 && out_fmt == AV_SAMPLE_FMT_U8 ) scale = 1L<<8; scale *= s->dither.scale; if (out_fmt == AV_SAMPLE_FMT_S32 && s->dither.output_sample_bits) scale *= 1<<(32-s->dither.output_sample_bits); s->dither.ns_pos = 0; s->dither.noise_scale= scale; s->dither.ns_scale = scale; s->dither.ns_scale_1 = scale ? 1/scale : 0; memset(s->dither.ns_errors, 0, sizeof(s->dither.ns_errors)); for (i=0; filters[i].coefs; i++) { const filter_t *f = &filters[i]; if (fabs(s->out_sample_rate - f->rate) / f->rate <= .05 && f->name == s->dither.method) { int j; s->dither.ns_taps = f->len; for (j=0; j<f->len; j++) s->dither.ns_coeffs[j] = f->coefs[j]; s->dither.ns_scale_1 *= 1 - exp(f->gain_cB * M_LN10 * 0.005) * 2 / (1<<(8*av_get_bytes_per_sample(out_fmt))); break; } } if (!filters[i].coefs && s->dither.method > SWR_DITHER_NS) { av_log(s, AV_LOG_WARNING, "Requested noise shaping dither not available at this sampling rate, using triangular hp dither\n"); s->dither.method = SWR_DITHER_TRIANGULAR_HIGHPASS; } av_assert0(!s->preout.count); s->dither.noise = s->preout; s->dither.temp = s->preout; if (s->dither.method > SWR_DITHER_NS) { s->dither.noise.bps = 4; s->dither.noise.fmt = AV_SAMPLE_FMT_FLTP; s->dither.noise_scale = 1; } return 0; }
DitherContext *ff_dither_alloc(AVAudioResampleContext *avr, enum AVSampleFormat out_fmt, enum AVSampleFormat in_fmt, int channels, int sample_rate) { AVLFG seed_gen; DitherContext *c; int ch; if (av_get_packed_sample_fmt(out_fmt) != AV_SAMPLE_FMT_S16 || av_get_bytes_per_sample(in_fmt) <= 2) { av_log(avr, AV_LOG_ERROR, "dithering %s to %s is not supported\n", av_get_sample_fmt_name(in_fmt), av_get_sample_fmt_name(out_fmt)); return NULL; } c = av_mallocz(sizeof(*c)); if (!c) return NULL; if (avr->dither_method == AV_RESAMPLE_DITHER_TRIANGULAR_NS && sample_rate != 48000 && sample_rate != 44100) { av_log(avr, AV_LOG_WARNING, "sample rate must be 48000 or 44100 Hz " "for triangular_ns dither. using triangular_hp instead.\n"); avr->dither_method = AV_RESAMPLE_DITHER_TRIANGULAR_HP; } c->method = avr->dither_method; dither_init(&c->ddsp, c->method); if (c->method == AV_RESAMPLE_DITHER_TRIANGULAR_NS) { if (sample_rate == 48000) { c->ns_coef_b = ns_48_coef_b; c->ns_coef_a = ns_48_coef_a; } else { c->ns_coef_b = ns_44_coef_b; c->ns_coef_a = ns_44_coef_a; } } /* Either s16 or s16p output format is allowed, but s16p is used internally, so we need to use a temp buffer and interleave if the output format is s16 */ if (out_fmt != AV_SAMPLE_FMT_S16P) { c->s16_data = ff_audio_data_alloc(channels, 1024, AV_SAMPLE_FMT_S16P, "dither s16 buffer"); if (!c->s16_data) goto fail; c->ac_out = ff_audio_convert_alloc(avr, out_fmt, AV_SAMPLE_FMT_S16P, channels, sample_rate); if (!c->ac_out) goto fail; } if (in_fmt != AV_SAMPLE_FMT_FLTP) { c->flt_data = ff_audio_data_alloc(channels, 1024, AV_SAMPLE_FMT_FLTP, "dither flt buffer"); if (!c->flt_data) goto fail; c->ac_in = ff_audio_convert_alloc(avr, AV_SAMPLE_FMT_FLTP, in_fmt, channels, sample_rate); if (!c->ac_in) goto fail; } c->state = av_mallocz(channels * sizeof(*c->state)); if (!c->state) goto fail; c->channels = channels; /* calculate thresholds for turning off dithering during periods of silence to avoid replacing digital silence with quiet dither noise */ c->mute_dither_threshold = lrintf(sample_rate * MUTE_THRESHOLD_SEC); c->mute_reset_threshold = c->mute_dither_threshold * 4; /* initialize dither states */ av_lfg_init(&seed_gen, 0xC0FFEE); for (ch = 0; ch < channels; ch++) { DitherState *state = &c->state[ch]; state->mute = c->mute_reset_threshold + 1; state->seed = av_lfg_get(&seed_gen); generate_dither_noise(c, state, FFMAX(32768, sample_rate / 2)); } return c; fail: ff_dither_free(&c); return NULL; }
static void set_audiodata_fmt(AudioData *a, enum AVSampleFormat fmt) { a->fmt = fmt; a->bps = av_get_bytes_per_sample(fmt); a->planar= av_sample_fmt_is_planar(fmt); }
AVFilterBufferRef *avfilter_default_get_audio_buffer(AVFilterLink *link, int perms, enum AVSampleFormat sample_fmt, int size, uint64_t channel_layout, int planar) { AVFilterBuffer *samples = av_mallocz(sizeof(AVFilterBuffer)); AVFilterBufferRef *ref = NULL; int i, sample_size, chans_nb, bufsize, per_channel_size, step_size = 0; char *buf; if (!samples || !(ref = av_mallocz(sizeof(AVFilterBufferRef)))) goto fail; ref->buf = samples; ref->format = sample_fmt; ref->audio = av_mallocz(sizeof(AVFilterBufferRefAudioProps)); if (!ref->audio) goto fail; ref->audio->channel_layout = channel_layout; ref->audio->size = size; ref->audio->planar = planar; /* make sure the buffer gets read permission or it's useless for output */ ref->perms = perms | AV_PERM_READ; samples->refcount = 1; samples->free = ff_avfilter_default_free_buffer; sample_size = av_get_bytes_per_sample(sample_fmt); chans_nb = av_get_channel_layout_nb_channels(channel_layout); per_channel_size = size/chans_nb; ref->audio->nb_samples = per_channel_size/sample_size; /* Set the number of bytes to traverse to reach next sample of a particular channel: * For planar, this is simply the sample size. * For packed, this is the number of samples * sample_size. */ for (i = 0; i < chans_nb; i++) samples->linesize[i] = planar > 0 ? per_channel_size : sample_size; memset(&samples->linesize[chans_nb], 0, (8-chans_nb) * sizeof(samples->linesize[0])); /* Calculate total buffer size, round to multiple of 16 to be SIMD friendly */ bufsize = (size + 15)&~15; buf = av_malloc(bufsize); if (!buf) goto fail; /* For planar, set the start point of each channel's data within the buffer * For packed, set the start point of the entire buffer only */ samples->data[0] = buf; if (buf && planar) { for (i = 1; i < chans_nb; i++) { step_size += per_channel_size; samples->data[i] = buf + step_size; } } else { for (i = 1; i < chans_nb; i++) samples->data[i] = buf; } memset(&samples->data[chans_nb], 0, (8-chans_nb) * sizeof(samples->data[0])); memcpy(ref->data, samples->data, sizeof(ref->data)); memcpy(ref->linesize, samples->linesize, sizeof(ref->linesize)); return ref; fail: if (ref) av_free(ref->audio); av_free(ref); av_free(samples); return NULL; }
static int encavcodecaInit(hb_work_object_t *w, hb_job_t *job) { AVCodec *codec; AVCodecContext *context; hb_audio_t *audio = w->audio; hb_work_private_t *pv = calloc(1, sizeof(hb_work_private_t)); w->private_data = pv; pv->job = job; pv->list = hb_list_init(); // channel count, layout and matrix encoding int matrix_encoding; uint64_t channel_layout = hb_ff_mixdown_xlat(audio->config.out.mixdown, &matrix_encoding); pv->out_discrete_channels = hb_mixdown_get_discrete_channel_count(audio->config.out.mixdown); // default settings and options AVDictionary *av_opts = NULL; const char *codec_name = NULL; enum AVCodecID codec_id = AV_CODEC_ID_NONE; enum AVSampleFormat sample_fmt = AV_SAMPLE_FMT_FLTP; int bits_per_raw_sample = 0; int profile = FF_PROFILE_UNKNOWN; // override with encoder-specific values switch (audio->config.out.codec) { case HB_ACODEC_AC3: codec_id = AV_CODEC_ID_AC3; if (matrix_encoding != AV_MATRIX_ENCODING_NONE) av_dict_set(&av_opts, "dsur_mode", "on", 0); break; case HB_ACODEC_FDK_AAC: case HB_ACODEC_FDK_HAAC: codec_name = "libfdk_aac"; sample_fmt = AV_SAMPLE_FMT_S16; bits_per_raw_sample = 16; switch (audio->config.out.codec) { case HB_ACODEC_FDK_HAAC: profile = FF_PROFILE_AAC_HE; break; default: profile = FF_PROFILE_AAC_LOW; break; } // Libav's libfdk-aac wrapper expects back channels for 5.1 // audio, and will error out unless we translate the layout if (channel_layout == AV_CH_LAYOUT_5POINT1) channel_layout = AV_CH_LAYOUT_5POINT1_BACK; break; case HB_ACODEC_FFAAC: codec_name = "aac"; av_dict_set(&av_opts, "stereo_mode", "ms_off", 0); break; case HB_ACODEC_FFFLAC: case HB_ACODEC_FFFLAC24: codec_id = AV_CODEC_ID_FLAC; switch (audio->config.out.codec) { case HB_ACODEC_FFFLAC24: sample_fmt = AV_SAMPLE_FMT_S32; bits_per_raw_sample = 24; break; default: sample_fmt = AV_SAMPLE_FMT_S16; bits_per_raw_sample = 16; break; } break; default: hb_error("encavcodecaInit: unsupported codec (0x%x)", audio->config.out.codec); return 1; } if (codec_name != NULL) { codec = avcodec_find_encoder_by_name(codec_name); if (codec == NULL) { hb_error("encavcodecaInit: avcodec_find_encoder_by_name(%s) failed", codec_name); return 1; } } else { codec = avcodec_find_encoder(codec_id); if (codec == NULL) { hb_error("encavcodecaInit: avcodec_find_encoder(%d) failed", codec_id); return 1; } } // allocate the context and apply the settings context = avcodec_alloc_context3(codec); hb_ff_set_sample_fmt(context, codec, sample_fmt); context->bits_per_raw_sample = bits_per_raw_sample; context->profile = profile; context->channel_layout = channel_layout; context->channels = pv->out_discrete_channels; context->sample_rate = audio->config.out.samplerate; if (audio->config.out.bitrate > 0) { context->bit_rate = audio->config.out.bitrate * 1000; } else if (audio->config.out.quality >= 0) { context->global_quality = audio->config.out.quality * FF_QP2LAMBDA; context->flags |= CODEC_FLAG_QSCALE; } if (audio->config.out.compression_level >= 0) { context->compression_level = audio->config.out.compression_level; } // For some codecs, libav requires the following flag to be set // so that it fills extradata with global header information. // If this flag is not set, it inserts the data into each // packet instead. context->flags |= CODEC_FLAG_GLOBAL_HEADER; if (hb_avcodec_open(context, codec, &av_opts, 0)) { hb_error("encavcodecaInit: hb_avcodec_open() failed"); return 1; } // avcodec_open populates the opts dictionary with the // things it didn't recognize. AVDictionaryEntry *t = NULL; while ((t = av_dict_get(av_opts, "", t, AV_DICT_IGNORE_SUFFIX))) { hb_log("encavcodecaInit: Unknown avcodec option %s", t->key); } av_dict_free(&av_opts); pv->context = context; audio->config.out.samples_per_frame = pv->samples_per_frame = context->frame_size; pv->input_samples = context->frame_size * context->channels; pv->input_buf = malloc(pv->input_samples * sizeof(float)); pv->max_output_bytes = (pv->input_samples * av_get_bytes_per_sample(context->sample_fmt)); // sample_fmt conversion if (context->sample_fmt != AV_SAMPLE_FMT_FLT) { pv->output_buf = malloc(pv->max_output_bytes); pv->avresample = avresample_alloc_context(); if (pv->avresample == NULL) { hb_error("encavcodecaInit: avresample_alloc_context() failed"); return 1; } av_opt_set_int(pv->avresample, "in_sample_fmt", AV_SAMPLE_FMT_FLT, 0); av_opt_set_int(pv->avresample, "out_sample_fmt", context->sample_fmt, 0); av_opt_set_int(pv->avresample, "in_channel_layout", context->channel_layout, 0); av_opt_set_int(pv->avresample, "out_channel_layout", context->channel_layout, 0); if (hb_audio_dither_is_supported(audio->config.out.codec)) { // dithering needs the sample rate av_opt_set_int(pv->avresample, "in_sample_rate", context->sample_rate, 0); av_opt_set_int(pv->avresample, "out_sample_rate", context->sample_rate, 0); av_opt_set_int(pv->avresample, "dither_method", audio->config.out.dither_method, 0); } if (avresample_open(pv->avresample)) { hb_error("encavcodecaInit: avresample_open() failed"); avresample_free(&pv->avresample); return 1; } } else { pv->avresample = NULL; pv->output_buf = pv->input_buf; } if (context->extradata != NULL) { memcpy(w->config->extradata.bytes, context->extradata, context->extradata_size); w->config->extradata.length = context->extradata_size; } return 0; }
int scan_metadata_ffmpeg(char *file, struct media_file_info *mfi) { AVFormatContext *ctx; const struct metadata_map *extra_md_map; enum CodecID codec_id; enum CodecID video_codec_id; enum CodecID audio_codec_id; AVStream *video_stream; AVStream *audio_stream; int mdcount; int i; int ret; ctx = NULL; #if LIBAVFORMAT_VERSION_MAJOR >= 53 || (LIBAVFORMAT_VERSION_MAJOR == 53 && LIBAVCODEC_VERSION_MINOR >= 3) ret = avformat_open_input(&ctx, file, NULL, NULL); #else ret = av_open_input_file(&ctx, file, NULL, 0, NULL); #endif if (ret != 0) { DPRINTF(E_WARN, L_SCAN, "Cannot open media file '%s': %s\n", file, strerror(AVUNERROR(ret))); return -1; } ret = av_find_stream_info(ctx); if (ret < 0) { DPRINTF(E_WARN, L_SCAN, "Cannot get stream info: %s\n", strerror(AVUNERROR(ret))); av_close_input_file(ctx); return -1; } #if 0 /* Dump input format as determined by ffmpeg */ # if LIBAVFORMAT_VERSION_MAJOR >= 52 || (LIBAVFORMAT_VERSION_MAJOR == 52 && LIBAVCODEC_VERSION_MINOR >= 101) av_dump_format(ctx, 0, file, 0); # else dump_format(ctx, 0, file, FALSE); # endif #endif DPRINTF(E_DBG, L_SCAN, "File has %d streams\n", ctx->nb_streams); /* Extract codec IDs, check for video */ video_codec_id = CODEC_ID_NONE; video_stream = NULL; audio_codec_id = CODEC_ID_NONE; audio_stream = NULL; for (i = 0; i < ctx->nb_streams; i++) { switch (ctx->streams[i]->codec->codec_type) { #if LIBAVCODEC_VERSION_MAJOR >= 53 || (LIBAVCODEC_VERSION_MAJOR == 52 && LIBAVCODEC_VERSION_MINOR >= 64) case AVMEDIA_TYPE_VIDEO: #else case CODEC_TYPE_VIDEO: #endif if (!video_stream) { DPRINTF(E_DBG, L_SCAN, "File has video (stream %d)\n", i); mfi->has_video = 1; video_stream = ctx->streams[i]; video_codec_id = video_stream->codec->codec_id; } break; #if LIBAVCODEC_VERSION_MAJOR >= 53 || (LIBAVCODEC_VERSION_MAJOR == 52 && LIBAVCODEC_VERSION_MINOR >= 64) case AVMEDIA_TYPE_AUDIO: #else case CODEC_TYPE_AUDIO: #endif if (!audio_stream) { audio_stream = ctx->streams[i]; audio_codec_id = audio_stream->codec->codec_id; } break; default: break; } } if (audio_codec_id == CODEC_ID_NONE) { DPRINTF(E_DBG, L_SCAN, "File has no audio streams, discarding\n"); av_close_input_file(ctx); return -1; } /* Common media information */ if (ctx->duration > 0) mfi->song_length = ctx->duration / (AV_TIME_BASE / 1000); /* ms */ if (ctx->bit_rate > 0) mfi->bitrate = ctx->bit_rate / 1000; else if (ctx->duration > AV_TIME_BASE) /* guesstimate */ mfi->bitrate = ((mfi->file_size * 8) / (ctx->duration / AV_TIME_BASE)) / 1000; DPRINTF(E_DBG, L_SCAN, "Duration %d ms, bitrate %d kbps\n", mfi->song_length, mfi->bitrate); /* Get some more information on the audio stream */ if (audio_stream) { if (audio_stream->codec->sample_rate != 0) mfi->samplerate = audio_stream->codec->sample_rate; /* Try sample format first */ #if LIBAVUTIL_VERSION_MAJOR >= 51 || (LIBAVUTIL_VERSION_MAJOR == 51 && LIBAVUTIL_VERSION_MINOR >= 4) mfi->bits_per_sample = 8 * av_get_bytes_per_sample(audio_stream->codec->sample_fmt); #elif LIBAVCODEC_VERSION_MAJOR >= 53 mfi->bits_per_sample = av_get_bits_per_sample_fmt(audio_stream->codec->sample_fmt); #else mfi->bits_per_sample = av_get_bits_per_sample_format(audio_stream->codec->sample_fmt); #endif if (mfi->bits_per_sample == 0) { /* Try codec */ mfi->bits_per_sample = av_get_bits_per_sample(audio_codec_id); } DPRINTF(E_DBG, L_SCAN, "samplerate %d, bps %d\n", mfi->samplerate, mfi->bits_per_sample); } /* Check codec */ extra_md_map = NULL; codec_id = (mfi->has_video) ? video_codec_id : audio_codec_id; switch (codec_id) { case CODEC_ID_AAC: DPRINTF(E_DBG, L_SCAN, "AAC\n"); mfi->type = strdup("m4a"); mfi->codectype = strdup("mp4a"); mfi->description = strdup("AAC audio file"); break; case CODEC_ID_ALAC: DPRINTF(E_DBG, L_SCAN, "ALAC\n"); mfi->type = strdup("m4a"); mfi->codectype = strdup("alac"); mfi->description = strdup("AAC audio file"); break; case CODEC_ID_FLAC: DPRINTF(E_DBG, L_SCAN, "FLAC\n"); mfi->type = strdup("flac"); mfi->codectype = strdup("flac"); mfi->description = strdup("FLAC audio file"); extra_md_map = md_map_vorbis; break; case CODEC_ID_MUSEPACK7: case CODEC_ID_MUSEPACK8: DPRINTF(E_DBG, L_SCAN, "Musepack\n"); mfi->type = strdup("mpc"); mfi->codectype = strdup("mpc"); mfi->description = strdup("Musepack audio file"); break; case CODEC_ID_MPEG4: /* Video */ case CODEC_ID_H264: DPRINTF(E_DBG, L_SCAN, "MPEG4 video\n"); mfi->type = strdup("m4v"); mfi->codectype = strdup("mp4v"); mfi->description = strdup("MPEG-4 video file"); extra_md_map = md_map_tv; break; case CODEC_ID_MP3: DPRINTF(E_DBG, L_SCAN, "MP3\n"); mfi->type = strdup("mp3"); mfi->codectype = strdup("mpeg"); mfi->description = strdup("MPEG audio file"); extra_md_map = md_map_id3; break; case CODEC_ID_VORBIS: DPRINTF(E_DBG, L_SCAN, "VORBIS\n"); mfi->type = strdup("ogg"); mfi->codectype = strdup("ogg"); mfi->description = strdup("Ogg Vorbis audio file"); extra_md_map = md_map_vorbis; break; case CODEC_ID_WMAVOICE: DPRINTF(E_DBG, L_SCAN, "WMA Voice\n"); mfi->type = strdup("wma"); mfi->codectype = strdup("wmav"); mfi->description = strdup("WMA audio file"); break; case CODEC_ID_WMAPRO: DPRINTF(E_DBG, L_SCAN, "WMA Pro\n"); mfi->type = strdup("wmap"); mfi->codectype = strdup("wma"); mfi->description = strdup("WMA audio file"); break; case CODEC_ID_WMALOSSLESS: DPRINTF(E_DBG, L_SCAN, "WMA Lossless\n"); mfi->type = strdup("wma"); mfi->codectype = strdup("wmal"); mfi->description = strdup("WMA audio file"); break; case CODEC_ID_WMAV1: case CODEC_ID_WMAV2: DPRINTF(E_DBG, L_SCAN, "WMA V1/V2\n"); mfi->type = strdup("wma"); mfi->codectype = strdup("wma"); mfi->description = strdup("WMA audio file"); break; case CODEC_ID_PCM_S16LE ... CODEC_ID_PCM_F64LE: if (strcmp(ctx->iformat->name, "aiff") == 0) { DPRINTF(E_DBG, L_SCAN, "AIFF\n"); mfi->type = strdup("aif"); mfi->codectype = strdup("aif"); mfi->description = strdup("AIFF audio file"); break; } else if (strcmp(ctx->iformat->name, "wav") == 0) { DPRINTF(E_DBG, L_SCAN, "WAV\n"); mfi->type = strdup("wav"); mfi->codectype = strdup("wav"); mfi->description = strdup("WAV audio file"); break; } /* WARNING: will fallthrough to default case, don't move */ /* FALLTHROUGH */ default: DPRINTF(E_DBG, L_SCAN, "Unknown codec 0x%x (video: %s), format %s (%s)\n", codec_id, (mfi->has_video) ? "yes" : "no", ctx->iformat->name, ctx->iformat->long_name); mfi->type = strdup("unkn"); mfi->codectype = strdup("unkn"); if (mfi->has_video) { mfi->description = strdup("Unknown video file format"); extra_md_map = md_map_tv; } else mfi->description = strdup("Unknown audio file format"); break; } mdcount = 0; if ((!ctx->metadata) && (!audio_stream->metadata) && (video_stream && !video_stream->metadata)) { DPRINTF(E_WARN, L_SCAN, "ffmpeg reports no metadata\n"); goto skip_extract; } if (extra_md_map) { ret = extract_metadata(mfi, ctx, audio_stream, video_stream, extra_md_map); mdcount += ret; DPRINTF(E_DBG, L_SCAN, "Picked up %d tags with extra md_map\n", ret); } #if LIBAVFORMAT_VERSION_MAJOR < 53 av_metadata_conv(ctx, NULL, ctx->iformat->metadata_conv); #endif ret = extract_metadata(mfi, ctx, audio_stream, video_stream, md_map_generic); mdcount += ret; DPRINTF(E_DBG, L_SCAN, "Picked up %d tags with generic md_map, %d tags total\n", ret, mdcount); /* fix up TV metadata */ if (mfi->media_kind == 10) { /* I have no idea why this is, but iTunes reports a media kind of 64 for stik==10 (?!) */ mfi->media_kind = 64; } /* Unspecified video files are "Movies", media_kind 2 */ else if (mfi->has_video == 1) { mfi->media_kind = 2; } skip_extract: if (mdcount == 0) { /* ffmpeg doesn't support FLAC nor Musepack metadata, * and is buggy for some WMA variants, so fall back to the * legacy format-specific parsers until it gets fixed */ if ((codec_id == CODEC_ID_WMAPRO) || (codec_id == CODEC_ID_WMAVOICE) || (codec_id == CODEC_ID_WMALOSSLESS)) { DPRINTF(E_WARN, L_SCAN, "Falling back to legacy WMA scanner\n"); av_close_input_file(ctx); return (scan_get_wmainfo(file, mfi) ? 0 : -1); } #ifdef FLAC else if (codec_id == CODEC_ID_FLAC) { DPRINTF(E_WARN, L_SCAN, "Falling back to legacy FLAC scanner\n"); av_close_input_file(ctx); return (scan_get_flacinfo(file, mfi) ? 0 : -1); } #endif /* FLAC */ #ifdef MUSEPACK else if ((codec_id == CODEC_ID_MUSEPACK7) || (codec_id == CODEC_ID_MUSEPACK8)) { DPRINTF(E_WARN, L_SCAN, "Falling back to legacy Musepack scanner\n"); av_close_input_file(ctx); return (scan_get_mpcinfo(file, mfi) ? 0 : -1); } #endif /* MUSEPACK */ else DPRINTF(E_WARN, L_SCAN, "Could not extract any metadata\n"); } /* Just in case there's no title set ... */ if (mfi->title == NULL) mfi->title = strdup(mfi->fname); /* All done */ av_close_input_file(ctx); return 0; }
void Movie::EncodeAudio(bool last) { AVStream *astream = av->fmt_ctx->streams[av->audio_stream_idx]; AVCodecContext *acodec = astream->codec; av_fifo_generic_write(av->audio_fifo, &audiobuf[0], audiobuf.size(), NULL); // bps: bytes per sample int channels = acodec->channels; int read_bps = 2; int write_bps = av_get_bytes_per_sample(acodec->sample_fmt); int max_read = acodec->frame_size * read_bps * channels; int min_read = last ? read_bps * channels : max_read; while (av_fifo_size(av->audio_fifo) >= min_read) { int read_bytes = MIN(av_fifo_size(av->audio_fifo), max_read); av_fifo_generic_read(av->audio_fifo, av->audio_data, read_bytes, NULL); // convert int read_samples = read_bytes / (read_bps * channels); int write_samples = read_samples; if (read_samples < acodec->frame_size) { // shrink or pad audio frame if (acodec->codec->capabilities & CODEC_CAP_SMALL_LAST_FRAME) acodec->frame_size = write_samples; else write_samples = acodec->frame_size; } convert_audio(read_samples, acodec->channels, -1, AV_SAMPLE_FMT_S16, av->audio_data, write_samples, acodec->channels, write_samples * write_bps, acodec->sample_fmt, av->audio_data_conv); #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55,28,1) avcodec_get_frame_defaults(av->audio_frame); #else av_frame_unref(av->audio_frame); #endif av->audio_frame->nb_samples = write_samples; av->audio_frame->pts = av_rescale_q(av->audio_counter, (AVRational){1, acodec->sample_rate}, acodec->time_base); av->audio_counter += write_samples; int asize = avcodec_fill_audio_frame(av->audio_frame, acodec->channels, acodec->sample_fmt, av->audio_data_conv, write_samples * write_bps * channels, 1); if (asize >= 0) { AVPacket pkt; memset(&pkt, 0, sizeof(AVPacket)); av_init_packet(&pkt); int got_pkt = 0; if (0 == avcodec_encode_audio2(acodec, &pkt, av->audio_frame, &got_pkt) && got_pkt) { if (pkt.pts != AV_NOPTS_VALUE && pkt.pts < pkt.dts) pkt.pts = pkt.dts; if (pkt.pts != AV_NOPTS_VALUE) pkt.pts = av_rescale_q(pkt.pts, acodec->time_base, astream->time_base); if (pkt.dts != AV_NOPTS_VALUE) pkt.dts = av_rescale_q(pkt.dts, acodec->time_base, astream->time_base); pkt.duration = av_rescale_q(pkt.duration, acodec->time_base, astream->time_base); pkt.stream_index = astream->index; av_interleaved_write_frame(av->fmt_ctx, &pkt); av_free_packet(&pkt); } } } if (last) { bool done = false; while (!done) { AVPacket pkt; memset(&pkt, 0, sizeof(AVPacket)); av_init_packet(&pkt); int got_pkt = 0; if (0 == avcodec_encode_audio2(acodec, &pkt, NULL, &got_pkt) && got_pkt) { if (pkt.pts != AV_NOPTS_VALUE && pkt.pts < pkt.dts) pkt.pts = pkt.dts; if (pkt.pts != AV_NOPTS_VALUE) pkt.pts = av_rescale_q(pkt.pts, acodec->time_base, astream->time_base); if (pkt.dts != AV_NOPTS_VALUE) pkt.dts = av_rescale_q(pkt.dts, acodec->time_base, astream->time_base); pkt.duration = av_rescale_q(pkt.duration, acodec->time_base, astream->time_base); pkt.stream_index = astream->index; av_interleaved_write_frame(av->fmt_ctx, &pkt); av_free_packet(&pkt); } else { done = true; } } } }