[FFmpeg-soc] G723.1 Frame Parser

Mohamed Naufal naufal11 at gmail.com
Tue Mar 30 14:16:43 CEST 2010


Hi

Here is the code for a frame parser i wrote for the g723.1 codec as my GSoC
qualification task

#include <stdint.h>
#include "libavutil/intreadwrite.h"

#include "avcodec.h"
#include "get_bits.h"

#define PITCH_MIN            18
#define FRM_LEN              240
#define SFRM_LEN             (FRM_LEN/4)
#define AD_CB_SIZE_HIGH_RATE 85         ///< 85 entry codebook for Frame6k3s
#define AD_CB_SIZE_LOW_RATE  170        ///< 170 entry codebook for
Frame5k3s

/*
 *  G723.1 frame types
 */
typedef enum {
    Frame6k3,           ///< 6.3 kbps frame rate
    Frame5k3,           ///< 5.3 kbps frame rate
    FrameSID,            ///< silence insertion descriptor frame
    FrameUntransmitted
} FrameType;

typedef enum {
    Rate6k3,
    Rate5k3
} Rate;

/*
 *  G723.1 unpacked data subframe
 */
typedef struct {
    uint16_t ad_cb_lag;     ///< adaptive codebook lag
    uint16_t pitch_lag;
    uint16_t combined_gain;
    uint16_t pulse_pos;
    uint16_t pulse_sign;
    uint16_t grid_index;
    uint16_t amp_index;     ///< for SID frames
} G723_1_Subframe;

/*
 *  G723.1 unpacked data frame
 */
typedef struct {
    uint32_t lsp_index;
    G723_1_Subframe subframe[4];
} G723_1_Frame;

typedef struct g723_1_context {
    G723_1_Frame frame;
    FrameType cur_frame_type;
    Rate cur_rate;
    int is_bad_frame;
} G723_1_Context;

/*
 * Unpack the frame into parameters
 *
 * @param p           the context
 * @param buf         pointer to the input buffer
 * @param buf_size    size of the input buffer
 */
static void unpack_bitstream(G723_1_Context *p, const uint8_t *buf,
                                       int buf_size)
{
    GetBitContext gb;
    G723_1_Frame *frame = &p->frame;
    uint32_t temp;

    init_get_bits(&gb, buf, buf_size * 8);

    // Extract frame type and rate info
    p->cur_frame_type = get_bits(&gb, 2);

    if (p->cur_frame_type == FrameUntransmitted)
        return;

    frame->lsp_index = get_bits(&gb, 24);

    if (p->cur_frame_type == FrameSID) {
        frame->subframe[0].amp_index = get_bits(&gb, 6);
        return;
    }

    // Extract the info common to both rates
    p->cur_rate = (p->cur_frame_type == 0) ? Rate6k3 : Rate5k3;

    temp = get_bits(&gb, 7);
    if (temp <= 123) {       // test if forbidden code
        frame->subframe[0].pitch_lag = temp + PITCH_MIN;
    }else {
        p->is_bad_frame  = 1; // transmission error
        return;
    }

    frame->subframe[1].ad_cb_lag  = get_bits(&gb, 2);

    temp = get_bits(&gb, 7);
    if (temp <= 123) {
        frame->subframe[1].pitch_lag = temp + PITCH_MIN;
    }else {
        p->is_bad_frame = 1;
        return;
    }

    frame->subframe[3].ad_cb_lag  = get_bits(&gb, 2);

    frame->subframe[0].ad_cb_lag  = 1;
    frame->subframe[2].ad_cb_lag  = 1;

    frame->subframe[0].combined_gain = get_bits(&gb, 12);
    frame->subframe[1].combined_gain = get_bits(&gb, 12);
    frame->subframe[2].combined_gain = get_bits(&gb, 12);
    frame->subframe[3].combined_gain = get_bits(&gb, 12);

    frame->subframe[0].grid_index = get_bits(&gb, 1);
    frame->subframe[1].grid_index = get_bits(&gb, 1);
    frame->subframe[2].grid_index = get_bits(&gb, 1);
    frame->subframe[3].grid_index = get_bits(&gb, 1);

    if (p->cur_frame_type == Frame6k3) {
        skip_bits(&gb, 1);  // skip reserved bit

        // Compute pulse_pos index using the 13bit combined position index
        temp = get_bits(&gb, 13);
        frame->subframe[0].pulse_pos = (temp / 90) / 9;
        frame->subframe[1].pulse_pos = (temp / 90) % 9;
        frame->subframe[2].pulse_pos = (temp % 90) / 9;
        frame->subframe[3].pulse_pos = (temp % 90) % 9;

        frame->subframe[0].pulse_pos = (frame->subframe[0].pulse_pos << 16)
+
                                       get_bits(&gb, 16);
        frame->subframe[1].pulse_pos = (frame->subframe[1].pulse_pos << 14)
+
                                       get_bits(&gb, 14);
        frame->subframe[2].pulse_pos = (frame->subframe[2].pulse_pos << 16)
+
                                       get_bits(&gb, 16);
        frame->subframe[3].pulse_pos = (frame->subframe[3].pulse_pos << 14)
+
                                       get_bits(&gb, 14);

        frame->subframe[0].pulse_sign = get_bits(&gb, 6);
        frame->subframe[1].pulse_sign = get_bits(&gb, 5);
        frame->subframe[2].pulse_sign = get_bits(&gb, 6);
        frame->subframe[3].pulse_sign = get_bits(&gb, 5);
    }else { // Frame5k3
        frame->subframe[0].pulse_pos  = get_bits(&gb, 12);
        frame->subframe[1].pulse_pos  = get_bits(&gb, 12);
        frame->subframe[2].pulse_pos  = get_bits(&gb, 12);
        frame->subframe[3].pulse_pos  = get_bits(&gb, 12);

        frame->subframe[0].pulse_sign = get_bits(&gb, 4);
        frame->subframe[1].pulse_sign = get_bits(&gb, 4);
        frame->subframe[2].pulse_sign = get_bits(&gb, 4);
        frame->subframe[3].pulse_sign = get_bits(&gb, 4);
    }
}

static int g723_1_parse_frame(AVCodecContext *avctx, void *data,
                               int *data_size, AVPacket *avpkt)
{
    G723_1_Context *p  = avctx->priv_data;
    const uint8_t *buf = avpkt->data;
    int buf_size       = avpkt->size;

    unpack_bitstream(p, buf, buf_size);

    if (p->is_bad_frame) {
        av_log_error(avctx, AV_LOG_ERROR, "Bad frame\n");
        return AVERROR_INVALIDDATA;
    }

    return 0;
}

AVCodec g723_1_decoder = {
    .name           = "g723_1",
    .type           = CODEC_TYPE_AUDIO,
    .id             = CODEC_ID_G723_1,
    .priv_data_size = sizeof(G723_1_Context),
    .decode         = g723_1_parse_frame,
    .long_name      = NULL_IF_CONFIG_SMALL("G.723.1"),
};


Naufal


More information about the FFmpeg-soc mailing list