예제 #1
0
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;
    }
}
예제 #2
0
/**
 * 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;
}
예제 #3
0
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);
}
예제 #4
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;
    }
}
예제 #5
0
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);
}
예제 #6
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;
}
예제 #7
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
    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;
}