[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