Example #1
0
static int decode_audio(struct dec_audio *da, struct mp_audio *buffer, int maxlen)
{
    struct ad_mpg123_context *con = da->priv;
    void *buf = buffer->planes[0];
    int ret;

    if (con->new_format) {
        ret = set_format(da);
        if (ret == MPG123_OK) {
            return 0; // let caller handle format change
        } else if (ret == MPG123_NEED_MORE) {
            con->need_data = true;
        } else {
            goto mpg123_fail;
        }
    }

    if (con->need_data) {
        if (feed_new_packet(da) < 0)
            return -1;
    }

    if (!mp_audio_config_equals(&da->decoded, buffer))
        return 0;

    size_t got_now = 0;
    ret = mpg123_replace_buffer(con->handle, buf, maxlen * con->sample_size);
    if (ret != MPG123_OK)
        goto mpg123_fail;

    ret = mpg123_decode_frame(con->handle, NULL, NULL, &got_now);

    int got_samples = got_now / con->sample_size;
    buffer->samples += got_samples;
    da->pts_offset += got_samples;

    if (ret == MPG123_NEW_FORMAT) {
        con->new_format = true;
    } else if (ret == MPG123_NEED_MORE) {
        con->need_data = true;
    } else if (ret != MPG123_OK && ret != MPG123_DONE) {
        goto mpg123_fail;
    }

    update_info(da);
    return 0;

mpg123_fail:
    MP_ERR(da, "mpg123 decoding error: %s\n",
           mpg123_strerror(con->handle));
    return -1;
}
Example #2
0
/* This tries to extract a requested amount of decoded data.
 * Even when you request 0 bytes, it will feed enough input so that
 * the decoder _could_ have delivered something.
 * Returns byte count >= 0, -1 on error.
 *
 * Thoughts on exact pts keeping:
 * We have to assume that MPEG frames are cut in pieces by packet boundaries.
 * Also, it might be possible that the first packet does not contain enough
 * data to ensure initial stream sync... or re-sync on erroneous streams.
 * So we need something robust to relate the decoded byte count to the correct
 * time stamp. This is tricky, though. From the outside, you cannot tell if,
 * after having fed two packets until the first output arrives, one should
 * start counting from the first packet's pts or the second packet's.
 * So, let's just count from the last fed package's pts. If the packets are
 * exactly cut to MPEG frames, this will cause one frame mismatch in the
 * beginning (when mpg123 peeks ahead for the following header), but will
 * be corrected with the third frame already. One might add special code to
 * not increment the base pts past the first packet's after a resync before
 * the first decoded bytes arrived. */
static int decode_a_bit(sh_audio_t *sh, unsigned char *buf, int count)
{
    int ret = MPG123_OK;
    int got = 0;
    struct ad_mpg123_context *con = sh->context;

    /* There will be one MPG123_NEW_FORMAT message on first open.
     * This will be handled in init(). */
    do {
        size_t got_now = 0;

        /* Feed the decoder. This will only fire from the second round on. */
        if (ret == MPG123_NEED_MORE) {
            int incount;
            double pts;
            unsigned char *inbuf;
            /* Feed more input data. */
            incount = ds_get_packet_pts(sh->ds, &inbuf, &pts);
            if (incount <= 0)
                break;          /* Apparently that's it. EOF. */

            /* Next bytes from that presentation time. */
            if (pts != MP_NOPTS_VALUE) {
                sh->pts       = pts;
                sh->pts_bytes = 0;
            }

#ifdef AD_MPG123_FRAMEWISE
            /* Have to use mpg123_feed() to avoid decoding here. */
            ret = mpg123_feed(con->handle, inbuf, incount);
#else
            /* Do not use mpg123_feed(), added in later libmpg123 versions. */
            ret = mpg123_decode(con->handle, inbuf, incount, NULL, 0, NULL);
#endif
            if (ret == MPG123_ERR)
                break;
        }
        /* Theoretically, mpg123 could return MPG123_DONE, so be prepared.
         * Should not happen in our usage, but it is a valid return code. */
        else if (ret == MPG123_ERR || ret == MPG123_DONE)
            break;

        /* Try to decode a bit. This is the return value that counts
         * for the loop condition. */
#ifdef AD_MPG123_FRAMEWISE
        if (!buf) { /* fake call just for feeding to get format */
            ret = mpg123_getformat(con->handle, NULL, NULL, NULL);
        } else { /* This is the decoding. One frame at a time. */
            ret = mpg123_replace_buffer(con->handle, buf, count);
            if (ret == MPG123_OK)
                ret = mpg123_decode_frame(con->handle, NULL, NULL, &got_now);
        }
#else
        ret = mpg123_decode(con->handle, NULL, 0, buf + got, count - got,
                            &got_now);
#endif

        got += got_now;
        sh->pts_bytes += got_now;

#ifdef AD_MPG123_FRAMEWISE
    } while (ret == MPG123_NEED_MORE || (got == 0 && count != 0));
#else
    } while (ret == MPG123_NEED_MORE || got < count);
Example #3
0
/****************************************************************************
 * DecodeBlock: the whole thing
 ****************************************************************************/
static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
{
    int i_err;
    block_t *p_block = pp_block ? *pp_block : NULL;
    decoder_sys_t *p_sys = p_dec->p_sys;

    if( !pp_block || !p_block )
        return NULL;

    if( p_block->i_buffer == 0 )
        return NULL;

    if( !date_Get( &p_sys->end_date ) && p_block->i_pts <= VLC_TS_INVALID )
    {
        /* We've just started the stream, wait for the first PTS. */
        msg_Dbg( p_dec, "waiting for PTS" );
        goto error;
    }

    if( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY | BLOCK_FLAG_CORRUPTED) )
    {
        date_Set( &p_sys->end_date, 0 );
        if( p_block->i_flags & BLOCK_FLAG_CORRUPTED )
            goto error;
    }

    /* Feed mpg123 with raw data */
    i_err = mpg123_feed( p_sys->p_handle, p_block->p_buffer,
                         p_block->i_buffer );

    if( i_err != MPG123_OK )
    {
        msg_Err( p_dec, "mpg123_feed failed: %s", mpg123_plain_strerror( i_err ) );
        goto error;
    }

    /* Get details about the stream */
    i_err = mpg123_info( p_sys->p_handle, &p_sys->frame_info );

    if( i_err == MPG123_NEED_MORE )
    {
        /* Need moar data */
        goto error;
    }
    else if( i_err != MPG123_OK )
    {
        msg_Err( p_dec, "mpg123_info failed: %s", mpg123_plain_strerror( i_err ) );
        goto error;
    }

    /* Configure the output */
    p_block->i_nb_samples = mpg123_spf( p_sys->p_handle );
    p_dec->fmt_out.i_bitrate = p_sys->frame_info.bitrate * 1000;

    switch( p_sys->frame_info.mode )
    {
        case MPG123_M_STEREO:
        case MPG123_M_JOINT:
            p_dec->fmt_out.audio.i_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
            break;
        case MPG123_M_DUAL:
            p_dec->fmt_out.audio.i_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
                                                     | AOUT_CHAN_DUALMONO;
            break;
        case MPG123_M_MONO:
            p_dec->fmt_out.audio.i_original_channels = AOUT_CHAN_CENTER;
            break;
        default:
            msg_Err( p_dec, "Unknown mode");
            goto error;
    }

    p_dec->fmt_out.audio.i_physical_channels =
        p_dec->fmt_out.audio.i_original_channels & AOUT_CHAN_PHYSMASK;

    /* Date management */
    if( p_dec->fmt_out.audio.i_rate != p_sys->frame_info.rate )
    {
        p_dec->fmt_out.audio.i_rate = p_sys->frame_info.rate;
        date_Init( &p_sys->end_date, p_dec->fmt_out.audio.i_rate, 1 );
        date_Set( &p_sys->end_date, 0 );
    }

    if( p_block->i_pts > VLC_TS_INVALID &&
        p_block->i_pts != date_Get( &p_sys->end_date ) )
    {
        date_Set( &p_sys->end_date, p_block->i_pts );
    }

    /* Request a new audio buffer */
    block_t *p_out = decoder_NewAudioBuffer( p_dec, p_block->i_nb_samples );
    if( unlikely( !p_out ) )
        goto error;

    /* Configure the buffer */
    p_out->i_nb_samples = p_block->i_nb_samples;
    p_out->i_dts = p_out->i_pts = date_Get( &p_sys->end_date );
    p_out->i_length = date_Increment( &p_sys->end_date, p_block->i_nb_samples )
        - p_out->i_pts;

    /* Make mpg123 write directly into the VLC output buffer */
    i_err = mpg123_replace_buffer( p_sys->p_handle, p_out->p_buffer, p_out->i_buffer );
    if( i_err != MPG123_OK )
    {
        msg_Err( p_dec, "could not replace buffer: %s", mpg123_plain_strerror( i_err ) );
        block_Release( p_out );
        goto error;
    }

    *pp_block = NULL; /* avoid being fed the same packet again */

    /* Do the actual decoding now */
    i_err = mpg123_decode_frame( p_sys->p_handle, NULL, NULL, NULL );
    if( i_err != MPG123_OK )
    {
        if( i_err != MPG123_NEW_FORMAT )
            msg_Err( p_dec, "mpg123_decode_frame error: %s", mpg123_plain_strerror( i_err ) );
        block_Release( p_out );
        goto error;
    }

    block_Release( p_block );
    return p_out;

error:
    block_Release( p_block );
    return NULL;
}
Example #4
0
/****************************************************************************
 * DecodeBlock: the whole thing
 ****************************************************************************/
static int DecodeBlock( decoder_t *p_dec, block_t *p_block )
{
    int i_err;
    decoder_sys_t *p_sys = p_dec->p_sys;
    block_t *p_out = NULL;

    if( !p_sys->b_opened )
    {
        if( p_block )
            block_Release( p_block );
        return VLCDEC_ECRITICAL;
    }

    /* Feed input block */
    if( p_block != NULL )
    {
        if( !date_Get( &p_sys->end_date ) && p_block->i_pts <= VLC_TS_INVALID )
        {
            /* We've just started the stream, wait for the first PTS. */
            msg_Dbg( p_dec, "waiting for PTS" );
            goto end;
        }

        if( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
        {
            Flush( p_dec );
            if( p_block->i_flags & BLOCK_FLAG_CORRUPTED )
                goto end;
        }

        /* Feed mpg123 with raw data */
        i_err = mpg123_feed( p_sys->p_handle, p_block->p_buffer,
                             p_block->i_buffer );

        if( i_err != MPG123_OK )
        {
            msg_Err( p_dec, "mpg123_feed failed: %s",
                     mpg123_plain_strerror( i_err ) );
            goto end;
        }
    }

    /* Fetch a new output block (if possible) */
    if( !p_sys->p_out
     || p_sys->p_out->i_buffer != mpg123_outblock( p_sys->p_handle ) )
    {
        if( p_sys->p_out )
            block_Release( p_sys->p_out );

        /* Keep the output buffer for next calls in case it's not used (in case
         * of MPG123_NEED_MORE status) */
        p_sys->p_out = block_Alloc( mpg123_outblock( p_sys->p_handle ) );

        if( unlikely( !p_sys->p_out ) )
            return VLCDEC_SUCCESS;
    }

    /* Do the actual decoding now */
    size_t i_bytes = 0;
    while( true )
    {
        /* Make mpg123 write directly into the VLC output buffer */
        i_err = mpg123_replace_buffer( p_sys->p_handle, p_sys->p_out->p_buffer,
                                       p_sys->p_out->i_buffer );
        if( i_err != MPG123_OK )
        {
            msg_Err( p_dec, "could not replace buffer: %s",
                     mpg123_plain_strerror( i_err ) );
            block_Release( p_sys->p_out );
            p_sys->p_out = NULL;
            return VLCDEC_SUCCESS;
        }

        i_err = mpg123_decode_frame( p_sys->p_handle, NULL, NULL, &i_bytes );
        if( i_err != MPG123_OK )
        {
            if( i_err == MPG123_NEW_FORMAT )
            {
                if( UpdateAudioFormat( p_dec ) != VLC_SUCCESS )
                    goto end;
                else
                    continue;
            }
            else if( i_err != MPG123_NEED_MORE )
                msg_Err( p_dec, "mpg123_decode_frame error: %s",
                         mpg123_plain_strerror( i_err ) );
        }
        else if( p_dec->fmt_out.audio.i_rate == 0 )
        {
            msg_Warn( p_dec, "mpg123_decode_frame returned valid frame without "
                             "updating the format" );
            if( UpdateAudioFormat( p_dec ) != VLC_SUCCESS )
                goto end;
        }
        break;
    }

    if( p_block && p_block->i_pts > VLC_TS_INVALID &&
        p_block->i_pts != date_Get( &p_sys->end_date ) )
        date_Set( &p_sys->end_date, p_block->i_pts );

    if( i_bytes == 0 )
        goto end;

    assert( p_dec->fmt_out.audio.i_rate != 0 );

    p_out = p_sys->p_out;
    p_sys->p_out = NULL;

    assert( p_out->i_buffer >= i_bytes );
    p_out->i_buffer = i_bytes;
    p_out->i_nb_samples = p_out->i_buffer * p_dec->fmt_out.audio.i_frame_length
                        / p_dec->fmt_out.audio.i_bytes_per_frame;

    /* Configure the buffer */
    p_out->i_dts = p_out->i_pts = date_Get( &p_sys->end_date );
    p_out->i_length = date_Increment( &p_sys->end_date, p_out->i_nb_samples )
        - p_out->i_pts;
end:
    if( p_block )
        block_Release( p_block );
    if( p_out != NULL )
        decoder_QueueAudio( p_dec, p_out );
    return VLCDEC_SUCCESS;
}