You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
rtpengine/lib/vp9.c

231 lines
4.8 KiB

#include "codecmod.h"
#include "loglib.h"
static void vp9_decode_frame(decoder_t *dec, frame_q *out) {
dec->dec_ts = dec->rtp_ts;
if (dec->packet_buffer->len) {
ilog(LOG_DEBUG, "Decoding %zu bytes of VP9", dec->packet_buffer->len);
avc_decoder_input(dec, &STR_GS(dec->packet_buffer), out, false);
}
g_string_truncate(dec->packet_buffer, 0);
}
static int vp9_decoder_input(decoder_t *dec, const str *data, frame_q *out, bool mark) {
if (!data)
goto err;
if (dec->rtp_ts != dec->dec_ts)
vp9_decode_frame(dec, out);
str frame = *data;
str b;
if (str_shift_ret(&frame, 1, &b))
goto err;
uint8_t iplfbevz = b.s[0];
if ((iplfbevz & 0x80)) { // I bit
if (str_shift_ret(&frame, 1, &b))
goto err;
uint8_t m_pid = b.s[0];
if ((m_pid & 0x80)) { // M bit
if (str_shift_ret(&frame, 1, &b))
goto err;
// XXX 2nd byte PID
}
}
if ((iplfbevz & 0x20)) { // L bit
if (str_shift_ret(&frame, 1, &b))
goto err;
//uint8_t tid_u_sid_d = b.s[0];
if (!(iplfbevz & 0x10)) {
// non-flexible mode
if (str_shift_ret(&frame, 1, &b))
goto err;
//uint8_t tl0picidx = b.s[0];
}
}
if ((iplfbevz & 0x50) == 0x50) { // both P and F
if (str_shift_ret(&frame, 1, &b))
goto err;
uint8_t p_diff_n0 = b.s[0];
if ((p_diff_n0 & 0x01)) {
if (str_shift_ret(&frame, 1, &b))
goto err;
uint8_t p_diff_n1 = b.s[0];
if ((p_diff_n1 & 0x01)) {
if (str_shift_ret(&frame, 1, &b))
goto err;
uint8_t p_diff_n2 = b.s[0];
if ((p_diff_n2 & 0x01))
goto err; // only max 3 allowed
}
}
}
if ((iplfbevz & 0x02)) { // V bit
if (str_shift_ret(&frame, 1, &b))
goto err;
uint8_t n_s_yg_RRR = b.s[0];
if ((n_s_yg_RRR & 0x10)) { // Y bit
uint8_t n_s = (n_s_yg_RRR >> 5) + 1;
for (uint8_t i = 0; i < n_s; i++) {
if (str_shift_ret(&frame, 4, &b))
goto err;
}
}
if ((n_s_yg_RRR & 0x08)) { // G bit
if (str_shift_ret(&frame, 1, &b))
goto err;
uint8_t n_g = b.s[0];
for (uint8_t i = 0; i < n_g; i++) {
if (str_shift_ret(&frame, 1, &b))
goto err;
uint8_t tid_u_r_RR = b.s[0];
uint8_t r = (tid_u_r_RR >> 2) & 0x3;
for (uint8_t j = 0; j < r; j++) {
if (str_shift_ret(&frame, 1, &b))
goto err;
//uint8_t p_diff = b.s[0];
}
}
}
}
g_string_append_len(dec->packet_buffer, frame.s, frame.len);
if (mark)
vp9_decode_frame(dec, out);
return 0;
err:
ilog(LOG_ERR | LOG_FLAG_LIMIT, "Invalid VP9 packet");
return -1;
}
static bool set_enc_options(encoder_t *enc, const str *codec_opts) {
// defaults
enc->avc.avcctx->gop_size = 10;
codeclib_set_av_opt_int(enc, "lag-in-frames", 0);
codeclib_set_av_opt_int(enc, "cpu-used", 8);
codeclib_set_av_opt_int(enc, "deadline", 5000);
codeclib_set_av_opt_int(enc, "threads", 8);
codeclib_key_value_parse(codec_opts, codeclib_avc_video_enc_options, enc);
return true;
}
static const codec_type_t codec_type_vp9 = {
.def_init = avc_def_init,
.decoder_init = avc_video_decoder_init,
.decoder_input = vp9_decoder_input,
.decoder_close = avc_decoder_close,
.encoder_init = avc_encoder_init,
.encoder_input = avc_video_encoder_input,
.encoder_close = avc_encoder_close,
};
static int packetizer_vp9_fn(AVPacket *pkt, str *output, size_t num_bytes, encoder_t *enc,
int64_t *__restrict pts, int64_t *__restrict duration, bool *mark)
{
size_t out_len = 0;
GString *buf = enc->sample_buffer;
output->s[0] = 0x80; // iplfbevz
out_len++;
if (pkt) {
if (pkt->size < 3)
return -1;
// new frame, move into buffer
g_string_truncate(buf, 0);
g_string_append_len(buf, (const char *) pkt->data, pkt->size);
ilog(LOG_DEBUG, "Packetising %u bytes of VP9", pkt->size);
enc->packet_pts = pkt->pts;
enc->frame_idx++;
output->s[0] |= 0x08; // B bit
}
output->s[1] = 0x80 | ((enc->frame_idx >> 8) & 0x7f); // M + PID
output->s[2] = enc->frame_idx & 0xff; // PID
out_len += 2;
size_t len = MIN(rtpe_common_config_ptr->video_pkt_size, output->len);
len = MIN(len, buf->len);
memcpy(output->s + out_len, buf->str, len);
out_len += len;
*pts = enc->packet_pts;
g_string_erase(buf, 0, len);
output->len = out_len;
*mark = false;
if (buf->len)
return 1;
*mark = true;
output->s[0] |= 0x04; // E bit
return 0;
}
packetizer_t packetizer_vp9 = {
.init = packetizer_buffered_init,
.fn = packetizer_vp9_fn,
.destroy = packetizer_buffered_destroy,
};
static const codec_def_t vp9 = {
.rtpname = "VP9",
.avcodec_id = AV_CODEC_ID_VP9,
.default_width = 1280,
.default_height = 720,
.avcodec_name_enc = "libvpx-vp9",
.avcodec_name_dec = "libvpx-vp9",
.default_bitrate = 2000000,
.packetizer = &packetizer_vp9,
.media_type = MT_VIDEO,
.codec_type = &codec_type_vp9,
.set_enc_options = set_enc_options,
.format_cmp = format_cmp_ignore,
.default_fmtp = "max-fr:30;max-fs:1800;profile-id=0",
};
__attribute__((constructor))
static void init(void) {
codeclib_register_codec(&vp9);
}