void movie_player::copy_audio_to_stream(uint8_t *pbStream, int iStreamSize) { std::lock_guard<std::mutex> audioLock(decoding_audio_mutex); bool fFirst = true; while(iStreamSize > 0 && !aborting) { if(audio_buffer_index >= audio_buffer_size) { int iAudioSize = decode_audio_frame(fFirst); fFirst = false; if(iAudioSize <= 0) { std::memset(audio_buffer, 0, audio_buffer_size); } else { audio_buffer_size = iAudioSize; } audio_buffer_index = 0; } int iCopyLength = audio_buffer_size - audio_buffer_index; if(iCopyLength > iStreamSize) { iCopyLength = iStreamSize; } std::memcpy(pbStream, (uint8_t *)audio_buffer + audio_buffer_index, iCopyLength); iStreamSize -= iCopyLength; pbStream += iCopyLength; audio_buffer_index += iCopyLength; } }
/** * Read one audio frame from the input file, decode, convert and store * it in the FIFO buffer. * @param fifo Buffer used for temporary storage * @param input_format_context Format context of the input file * @param input_codec_context Codec context of the input file * @param output_codec_context Codec context of the output file * @param resampler_context Resample context for the conversion * @param[out] finished Indicates whether the end of file has * been reached and all data has been * decoded. If this flag is false, * there is more data to be decoded, * i.e., this function has to be called * again. * @return Error code (0 if successful) */ int Transcode::read_decode_convert_and_store(AVAudioFifo *fifo, AVFormatContext *input_format_context, AVCodecContext *input_codec_context, AVCodecContext *output_codec_context, SwrContext *resampler_context, int *finished) { /* Temporary storage of the input samples of the frame read from the file. */ AVFrame *input_frame = NULL; /* Temporary storage for the converted input samples. */ uint8_t **converted_input_samples = NULL; int data_present; int ret = AVERROR_EXIT; /* Initialize temporary storage for one input frame. */ if (init_input_frame(&input_frame)) goto cleanup; /* Decode one frame worth of audio samples. */ if (decode_audio_frame(input_frame, input_format_context, input_codec_context, &data_present, finished)) goto cleanup; /* If we are at the end of the file and there are no more samples * in the decoder which are delayed, we are actually finished. * This must not be treated as an error. */ if (*finished && !data_present) { ret = 0; goto cleanup; } /* If there is decoded data, convert and store it. */ if (data_present) { /* Initialize the temporary storage for the converted input samples. */ if (init_converted_samples(&converted_input_samples, output_codec_context, input_frame->nb_samples)) goto cleanup; /* Convert the input samples to the desired output sample format. * This requires a temporary storage provided by converted_input_samples. */ if (convert_samples((const uint8_t**)input_frame->extended_data, converted_input_samples, input_frame->nb_samples, resampler_context)) goto cleanup; /* Add the converted input samples to the FIFO buffer for later processing. */ if (add_samples_to_fifo(fifo, converted_input_samples, input_frame->nb_samples)) goto cleanup; ret = 0; } ret = 0; cleanup: if (converted_input_samples) { av_freep(&converted_input_samples[0]); free(converted_input_samples); } av_frame_free(&input_frame); return ret; }
void AudioLoader::flushPacket() { AVPacket empty; do { _dataSize = FFMPEG_BUFFER_SIZE * sizeof(int16_t); empty.data = 0; empty.size = 0; decode_audio_frame(_audioCtx, _buffer, &_dataSize, &empty); copyFFmpegOutput(); } while (_dataSize > 0); }
void audio_callback (void *userdata, Uint8 *stream, int len) { static uint8_t silence_buf[SDL_AUDIO_BUFFER_SIZE] = {0}; static uint8_t *buf = NULL; static size_t buf_size = 0; static size_t buf_index = 0; PlayerContext *ctx = userdata; int send_len, decoded_size; while (len > 0 && !quit) { if (buf_index >= buf_size) { decoded_size = decode_audio_frame (ctx, &buf); if (decoded_size < 0) { av_log (NULL, AV_LOG_WARNING, "Could not decode audio frame"); buf = silence_buf; buf_size = sizeof silence_buf; } else { buf_size = decoded_size; } buf_index = 0; } send_len = buf_size - buf_index; if (send_len > len) { send_len = len; } memcpy (stream, buf + buf_index, send_len); len -= send_len; stream += send_len; buf_index += send_len; } }
void AudioLoader::flushPacket() { AVPacket empty; av_init_packet(&empty); do { _dataSize = FFMPEG_BUFFER_SIZE; empty.data = NULL; empty.size = 0; int len = decode_audio_frame(_audioCtx, _buffer, &_dataSize, &empty); if (len < 0) { char errstring[1204]; av_strerror(len, errstring, sizeof(errstring)); ostringstream msg; msg << "AudioLoader: decoding error while flushing a packet:" << errstring; E_WARNING(msg.str()); } copyFFmpegOutput(); } while (_dataSize > 0); }
/** * Gets the AVPacket stored in _packet, and decodes all the samples it can from it, * putting them in _buffer, the total number of bytes written begin stored in _dataSize. */ int AudioLoader::decodePacket() { /* E_DEBUG(EAlgorithm, "-----------------------------------------------------"); E_DEBUG(EAlgorithm, "decoding packet of " << _packet.size << " bytes"); E_DEBUG(EAlgorithm, "pts: " << _packet.pts << " - dts: " << _packet.dts); //" - pos: " << pkt->pos); E_DEBUG(EAlgorithm, "flags: " << _packet.flags); E_DEBUG(EAlgorithm, "duration: " << _packet.duration); */ int len = 0; // buff is an offset in our output buffer, it points to where we should start // writing the next decoded samples float* buff = _buffer; // _dataSize gets the size of the buffer, in bytes _dataSize = FFMPEG_BUFFER_SIZE; // Note: md5 should be computed before decoding frame, as the decoding may // change the content of a packet. Still, not sure if it is correct to // compute md5 over packet which contains incorrect frames, potentially // belonging to id3 metadata (TODO: or is it just a missing header issue?), // but computing md5 hash using ffmpeg will also treat it as audio: // ffmpeg -i file.mp3 -acodec copy -f md5 - len = decode_audio_frame(_audioCtx, buff, &_dataSize, &_packet); if (len < 0) { char errstring[1204]; av_strerror(len, errstring, sizeof(errstring)); ostringstream msg; if (_audioCtx->codec_id == AV_CODEC_ID_MP3) { msg << "AudioLoader: invalid frame, skipping it: " << errstring; // mp3 streams can have tag frames (id3v2?) which libavcodec tries to // read as audio anyway, and we probably don't want print an error // message for that... // TODO: Are these frames really id3 tags? //E_DEBUG(EAlgorithm, msg); E_WARNING(msg.str()); } else { msg << "AudioLoader: error while decoding, skipping frame: " << errstring; E_WARNING(msg.str()); } return 0; } if (len != _packet.size) { // https://www.ffmpeg.org/doxygen/trunk/group__lavc__decoding.html#ga834bb1b062fbcc2de4cf7fb93f154a3e // Some decoders may support multiple frames in a single AVPacket. Such // decoders would then just decode the first frame and the return value // would be less than the packet size. In this case, avcodec_decode_audio4 // has to be called again with an AVPacket containing the remaining data // in order to decode the second frame, etc... Even if no frames are // returned, the packet needs to be fed to the decoder with remaining // data until it is completely consumed or an error occurs. E_WARNING("AudioLoader: more than 1 frame in packet, decoding remaining bytes..."); E_WARNING("at sample index: " << output("audio").totalProduced()); E_WARNING("decoded samples: " << len); E_WARNING("packet size: " << _packet.size); } // update packet data pointer to data left undecoded (if any) _packet.size -= len; _packet.data += len; if (_dataSize <= 0) { // No data yet, get more frames // cout << "no data yet, get more frames" << endl; _dataSize = 0; } return len; }
/** * Gets the AVPacket stored in _packet, and decodes all the samples it can from it, * putting them in _buffer, the total number of bytes written begin stored in _dataSize. */ int AudioLoader::decodePacket() { /* E_DEBUG(EAlgorithm, "-----------------------------------------------------"); E_DEBUG(EAlgorithm, "decoding packet of " << _packet.size << " bytes"); E_DEBUG(EAlgorithm, "pts: " << _packet.pts << " - dts: " << _packet.dts); //" - pos: " << pkt->pos); E_DEBUG(EAlgorithm, "flags: " << _packet.flags); E_DEBUG(EAlgorithm, "duration: " << _packet.duration); */ int len = 0; // buff is an offset in our output buffer, it points to where we should start // writing the next decoded samples int16_t* buff = _buffer; #if !HAVE_SWRESAMPLE if (_audioConvert) { buff = _buff1; } #endif // _dataSize gets the size of the buffer, in bytes _dataSize = FFMPEG_BUFFER_SIZE*sizeof(int16_t); // _dataSize input = number of bytes available for write in buff // output = number of bytes actually written (actual: S16 data) //E_DEBUG(EAlgorithm, "decode_audio_frame, available bytes in buffer = " << _dataSize); len = decode_audio_frame(_audioCtx, buff, &_dataSize, &_packet); if (len < 0) { // only print error msg when file is not an mp3, because mp3 streams can have tag // frames (id3v2?) which libavcodec tries to read as audio anyway, and we don't want // to print an error message for that... if (_audioCtx->codec_id == CODEC_ID_MP3) { E_DEBUG(EAlgorithm, "AudioLoader: invalid frame, probably an mp3 tag frame, skipping it"); } else { E_WARNING("AudioLoader: error while decoding, skipping frame"); } return 0; } if (_dataSize <= 0) { // No data yet, get more frames //cout << "no data yet, get more frames" << endl; _dataSize = 0; return 0; } #if !HAVE_SWRESAMPLE if (_audioConvert) { // this assumes that all audio is interleaved in the first channel // it works as we're only doing sample format conversion, but we // should be very careful const void* ibuf[6] = { buff }; void* obuf[6] = { _buff2 }; int istride[6] = { av_get_bytes_per_sample(_audioCtx->sample_fmt) }; int ostride[6] = { av_get_bytes_per_sample(AV_SAMPLE_FMT_S16) }; int totalsamples = _dataSize / istride[0]; // == num_samp_per_channel * num_channels if (av_audio_convert(_audioConvert, obuf, ostride, ibuf, istride, totalsamples) < 0) { ostringstream msg; msg << "AudioLoader: Error converting " << " from " << avcodec_get_sample_fmt_name(_audioCtx->sample_fmt) << " to " << avcodec_get_sample_fmt_name(SAMPLE_FMT_S16); throw EssentiaException(msg); } // when entering the current block, dataSize contained the size in bytes // that the audio was taking in its native format. Now it needs to be set // to the size of the audio we're returning, after conversion _dataSize = totalsamples * av_get_bytes_per_sample(AV_SAMPLE_FMT_S16); memcpy(_buffer, _buff2, _dataSize); } #endif if (len != _packet.size) { // FIXME: investigate why this happens and whether it is a big issue // (looks like it only loses silent samples at the end of files) // more than 1 frame in a packet, happens a lot with flac for instance... E_WARNING("AudioLoader: more than 1 frame in packet, dropping remaining bytes..."); E_WARNING("at sample index: " << output("audio").totalProduced()); E_WARNING("decoded samples: " << len); E_WARNING("packet size: " << _packet.size); } return len; }