FS-8688 #resolve [Implement VP9 draft uberti payload 01 and libVPX 1.5]

This commit is contained in:
Anthony Minessale 2016-02-03 18:36:17 -06:00
parent 2b5f40b38e
commit 5b456b395c
3 changed files with 253 additions and 47 deletions

View File

@ -1274,11 +1274,27 @@ PKG_CHECK_MODULES([SNDFILE], [sndfile >= 1.0.20],[
AM_CONDITIONAL([HAVE_SNDFILE],[true])],[ AM_CONDITIONAL([HAVE_SNDFILE],[true])],[
AC_MSG_RESULT([no]); AM_CONDITIONAL([HAVE_SNDFILE],[false])]) AC_MSG_RESULT([no]); AM_CONDITIONAL([HAVE_SNDFILE],[false])])
PKG_CHECK_MODULES([VPX], [vpx2 >= 1.4.0],[ ac_cv_have_vpx=no
AM_CONDITIONAL([HAVE_VPX],[true])],[ PKG_CHECK_MODULES([VPX], [vpx2 >= 1.5.0],[
PKG_CHECK_MODULES([VPX], [vpx >= 1.4.0],[ ac_cv_have_vpx=yes],[
AM_CONDITIONAL([HAVE_VPX],[true])],[ PKG_CHECK_MODULES([VPX], [vpx >= 1.5.0],[
AC_MSG_RESULT([no]); AM_CONDITIONAL([HAVE_VPX],[false])])]) ac_cv_have_vpx=yes],[
AC_MSG_RESULT([no]); ac_cv_have_vpx=no])])
vpx_atleast_15=no
if test x"$ac_cv_have_vpx" = xyes; then
AC_MSG_CHECKING(whether libvpx is at least version 1.5)
save_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${VPX_CFLAGS} ${save_CPPFLAGS}"
AC_TRY_COMPILE([
#include <vpx/vpx_image.h>
], [vpx_color_range_t foo = VPX_CR_FULL_RANGE;],[vpx_atleast_15=yes],[vpx_atleast_15=no])
AC_MSG_RESULT($vpx_atleast_15)
CPPFLAGS="${save_CPPFLAGS}"
fi
AM_CONDITIONAL([HAVE_VPX],[test "x$vpx_atleast_15" != "xno"])
SWITCH_AM_CFLAGS="$VPX_CFLAGS $SWITCH_AM_CFLAGS" SWITCH_AM_CFLAGS="$VPX_CFLAGS $SWITCH_AM_CFLAGS"
SWITCH_AM_CXXFLAGS="$VPX_CFLAGS $SWITCH_AM_CXXFLAGS" SWITCH_AM_CXXFLAGS="$VPX_CFLAGS $SWITCH_AM_CXXFLAGS"

View File

@ -78,10 +78,17 @@ extern "C" {
VPX_CS_SRGB = 7 /**< sRGB */ VPX_CS_SRGB = 7 /**< sRGB */
} vpx_color_space_t; /**< alias for enum vpx_color_space */ } vpx_color_space_t; /**< alias for enum vpx_color_space */
/*!\brief List of supported color range */
typedef enum vpx_color_range {
VPX_CR_STUDIO_RANGE = 0, /**< Y [16..235], UV [16..240] */
VPX_CR_FULL_RANGE = 1 /**< YUV/RGB [0..255] */
} vpx_color_range_t; /**< alias for enum vpx_color_range */
/**\brief Image Descriptor */ /**\brief Image Descriptor */
typedef struct vpx_image { typedef struct vpx_image {
vpx_img_fmt_t fmt; /**< Image Format */ vpx_img_fmt_t fmt; /**< Image Format */
vpx_color_space_t cs; /**< Color Space */ vpx_color_space_t cs; /**< Color Space */
vpx_color_range_t range; /**< Color Range */
/* Image storage dimensions */ /* Image storage dimensions */
unsigned int w; /**< Stored image width */ unsigned int w; /**< Stored image width */
@ -92,6 +99,10 @@ extern "C" {
unsigned int d_w; /**< Displayed image width */ unsigned int d_w; /**< Displayed image width */
unsigned int d_h; /**< Displayed image height */ unsigned int d_h; /**< Displayed image height */
/* Image intended rendering dimensions */
unsigned int r_w; /**< Intended rendering image width */
unsigned int r_h; /**< Intended rendering image height */
/* Chroma subsampling info */ /* Chroma subsampling info */
unsigned int x_chroma_shift; /**< subsampling order, X */ unsigned int x_chroma_shift; /**< subsampling order, X */
unsigned int y_chroma_shift; /**< subsampling order, Y */ unsigned int y_chroma_shift; /**< subsampling order, Y */

View File

@ -41,7 +41,6 @@
#define SLICE_SIZE SWITCH_DEFAULT_VIDEO_SIZE #define SLICE_SIZE SWITCH_DEFAULT_VIDEO_SIZE
#define KEY_FRAME_MIN_FREQ 250000 #define KEY_FRAME_MIN_FREQ 250000
/* http://tools.ietf.org/html/draft-ietf-payload-vp8-10 /* http://tools.ietf.org/html/draft-ietf-payload-vp8-10
The first octets after the RTP header are the VP8 payload descriptor, with the following structure. The first octets after the RTP header are the VP8 payload descriptor, with the following structure.
@ -96,26 +95,30 @@ typedef struct {
unsigned pid:3; unsigned pid:3;
} vp8_payload_descriptor_t; } vp8_payload_descriptor_t;
#ifdef WHAT_THEY_FUCKING_SAY
typedef struct { typedef struct {
unsigned have_pid:1; unsigned have_pid:1;
unsigned have_p_layer:1;
unsigned have_layer_ind:1; unsigned have_layer_ind:1;
unsigned have_ref_ind:1; unsigned is_flexible:1;
unsigned start:1; unsigned start:1;
unsigned end:1; unsigned end:1;
unsigned have_ss:1; unsigned have_ss:1;
unsigned have_su:1;
unsigned zero:1; unsigned zero:1;
} vp9_payload_descriptor_t; } vp9_payload_descriptor_t;
#else
typedef struct { typedef struct {
unsigned dunno:6; unsigned n_s:3;
unsigned start:1; unsigned y:1;
unsigned key:1; unsigned g:1;
} vp9_payload_descriptor_t; unsigned zero:0;
#endif } vp9_ss_t;
typedef struct {
unsigned t:3;
unsigned u:1;
unsigned r:2;
unsigned zero:2;
} vp9_n_g_t;
#else /* ELSE LITTLE */ #else /* ELSE LITTLE */
@ -128,24 +131,36 @@ typedef struct {
unsigned extended:1; unsigned extended:1;
} vp8_payload_descriptor_t; } vp8_payload_descriptor_t;
#ifdef WHAT_THEY_FUCKING_SAY
typedef struct { typedef struct {
unsigned zero:1; unsigned zero:1;
unsigned have_su:1;
unsigned have_ss:1; unsigned have_ss:1;
unsigned end:1; unsigned end:1;
unsigned start:1; unsigned start:1;
unsigned have_ref_ind:1; unsigned is_flexible:1;
unsigned have_layer_ind:1; unsigned have_layer_ind:1;
unsigned have_p_layer:1;
unsigned have_pid:1; unsigned have_pid:1;
} vp9_payload_descriptor_t; } vp9_payload_descriptor_t;
#else
typedef struct { typedef struct {
unsigned key:1; unsigned zero:4;
unsigned start:1; unsigned g:1;
unsigned dunno:6; unsigned y:1;
} vp9_payload_descriptor_t; unsigned n_s:3;
#endif } vp9_ss_t;
typedef struct {
unsigned zero:2;
unsigned r:2;
unsigned u:1;
unsigned t:3;
} vp9_n_g_t;
typedef struct {
unsigned d:1;
unsigned s:3;
unsigned gof_idx:4;
} vp9_layer_t;
#endif #endif
@ -154,6 +169,37 @@ typedef union {
vp9_payload_descriptor_t vp9; vp9_payload_descriptor_t vp9;
} vpx_payload_descriptor_t; } vpx_payload_descriptor_t;
#define kMaxVp9NumberOfSpatialLayers 16
typedef struct {
switch_bool_t has_received_sli;
uint8_t picture_id_sli;
switch_bool_t has_received_rpsi;
uint64_t picture_id_rpsi;
int16_t picture_id; // Negative value to skip pictureId.
switch_bool_t inter_pic_predicted; // This layer frame is dependent on previously
// coded frame(s).
switch_bool_t flexible_mode;
switch_bool_t ss_data_available;
int tl0_pic_idx; // Negative value to skip tl0PicIdx.
uint8_t temporal_idx;
uint8_t spatial_idx;
switch_bool_t temporal_up_switch;
switch_bool_t inter_layer_predicted; // Frame is dependent on directly lower spatial
// layer frame.
uint8_t gof_idx;
// SS data.
size_t num_spatial_layers;
switch_bool_t spatial_layer_resolution_present;
uint16_t width[kMaxVp9NumberOfSpatialLayers];
uint16_t height[kMaxVp9NumberOfSpatialLayers];
// GofInfoVP9 gof;
} vp9_info_t;
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma pack(pop, r1) #pragma pack(pop, r1)
#endif #endif
@ -191,7 +237,7 @@ static inline int IS_VP8_KEY_FRAME(uint8_t *data)
} }
} }
#define IS_VP9_KEY_FRAME(byte) ((byte) & 0x01) #define IS_VP9_KEY_FRAME(byte) ((((byte) & 0x10) == 0) && ((byte) & 0x02))
#define IS_VP9_START_PKT(byte) ((byte) & 0x02) #define IS_VP9_START_PKT(byte) ((byte) & 0x02)
SWITCH_MODULE_LOAD_FUNCTION(mod_vpx_load); SWITCH_MODULE_LOAD_FUNCTION(mod_vpx_load);
@ -200,6 +246,7 @@ SWITCH_MODULE_DEFINITION(mod_vpx, mod_vpx_load, NULL, NULL);
struct vpx_context { struct vpx_context {
switch_codec_t *codec; switch_codec_t *codec;
int is_vp9; int is_vp9;
vp9_info_t vp9;
int lossless; int lossless;
vpx_codec_iface_t *encoder_interface; vpx_codec_iface_t *encoder_interface;
vpx_codec_iface_t *decoder_interface; vpx_codec_iface_t *decoder_interface;
@ -330,7 +377,7 @@ static switch_status_t init_encoder(switch_codec_t *codec)
context->pkt = NULL; context->pkt = NULL;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(codec->session), SWITCH_LOG_DEBUG1, switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(codec->session), SWITCH_LOG_NOTICE,
"VPX reset encoder picture from %dx%d to %dx%d %u BW\n", "VPX reset encoder picture from %dx%d to %dx%d %u BW\n",
config->g_w, config->g_h, context->codec_settings.video.width, context->codec_settings.video.height, context->bandwidth); config->g_w, config->g_h, context->codec_settings.video.width, context->codec_settings.video.height, context->bandwidth);
@ -358,6 +405,11 @@ static switch_status_t init_encoder(switch_codec_t *codec)
config->rc_max_quantizer = 63; config->rc_max_quantizer = 63;
} }
config->temporal_layering_mode = VP9E_TEMPORAL_LAYERING_MODE_NOLAYERING;
config->ts_number_layers = 1;
config->ts_rate_decimator[0] = 1;
config->ts_periodicity = 1;
config->ts_layer_id[0] = 0;
} else { } else {
// settings // settings
@ -425,7 +477,7 @@ static switch_status_t init_encoder(switch_codec_t *codec)
} }
} else if (context->flags & SWITCH_CODEC_FLAG_ENCODE) { } else if (context->flags & SWITCH_CODEC_FLAG_ENCODE) {
// #define SHOW(field) fprintf(stderr, " %-28s = %d\n", #field, config->field); // #define SHOW(field) fprintf(stderr, " %-28s = %d\n", #field, config->field);
#ifdef SHOW #ifdef SHOW
fprintf(stderr, "Codec: %s\n", vpx_codec_iface_name(context->encoder_interface)); fprintf(stderr, "Codec: %s\n", vpx_codec_iface_name(context->encoder_interface));
@ -606,7 +658,59 @@ static switch_status_t consume_partition(vpx_context_t *context, switch_frame_t
if (context->is_vp9) { if (context->is_vp9) {
payload_descriptor->vp9.start = start; payload_descriptor->vp9.start = start;
payload_descriptor->vp9.key = key;
if (1) {
// payload_descriptor->vp9.have_p_layer = key; // key?
payload_descriptor->vp9.have_pid = 0;
if (start) {
// context->vp9.picture_id++;
}
// if (context->vp9.picture_id > 0x7f) { // todo rewind to 0
// *body++ = context->vp9.picture_id >> 8;
// *body++ = context->vp9.picture_id & 0xff;
// payload_size--;
// frame->datalen++;
// } else {
// *body++ = context->vp9.picture_id;
// }
// payload_size--;
// frame->datalen++;
if (key) {
vp9_ss_t *ss = (vp9_ss_t *)body;
payload_descriptor->vp9.have_ss = 1;
ss->n_s = 0;
ss->g = 0;
ss->y = 0;
ss->zero = 0;
body++;
payload_size--;
frame->datalen++;
if (0) { // y ?
uint16_t *w;
uint16_t *h;
ss->y = 1;
w = (uint16_t *)body;
body+=2;
h = (uint16_t *)body;
body+=2;
*w = (uint16_t)context->codec_settings.video.width;
*h = (uint16_t)context->codec_settings.video.height;
payload_size-= (ss->n_s + 1) * 4;
frame->datalen+= (ss->n_s + 1) * 4;
}
}
}
} else { } else {
payload_descriptor->vp8.start = start; payload_descriptor->vp8.start = start;
} }
@ -623,9 +727,13 @@ static switch_status_t consume_partition(vpx_context_t *context, switch_frame_t
frame->m = 0; frame->m = 0;
return SWITCH_STATUS_MORE_DATA; return SWITCH_STATUS_MORE_DATA;
} }
if (frame->m && context->is_vp9) {
payload_descriptor->vp9.end = 1;
}
} }
static void reset_codec_encoder(switch_codec_t *codec) static switch_status_t reset_codec_encoder(switch_codec_t *codec)
{ {
vpx_context_t *context = (vpx_context_t *)codec->private_info; vpx_context_t *context = (vpx_context_t *)codec->private_info;
@ -637,7 +745,7 @@ static void reset_codec_encoder(switch_codec_t *codec)
context->framecount = 0; context->framecount = 0;
context->encoder_init = 0; context->encoder_init = 0;
context->pkt = NULL; context->pkt = NULL;
init_encoder(codec); return init_encoder(codec);
} }
static switch_status_t switch_vpx_encode(switch_codec_t *codec, switch_frame_t *frame) static switch_status_t switch_vpx_encode(switch_codec_t *codec, switch_frame_t *frame)
@ -656,7 +764,9 @@ static switch_status_t switch_vpx_encode(switch_codec_t *codec, switch_frame_t *
} }
if (context->need_encoder_reset != 0) { if (context->need_encoder_reset != 0) {
reset_codec_encoder(codec); if (reset_codec_encoder(codec) != SWITCH_STATUS_SUCCESS) {
return SWITCH_STATUS_FALSE;
}
context->need_encoder_reset = 0; context->need_encoder_reset = 0;
} }
@ -678,13 +788,17 @@ static switch_status_t switch_vpx_encode(switch_codec_t *codec, switch_frame_t *
if (!context->encoder_init) { if (!context->encoder_init) {
init_encoder(codec); if (init_encoder(codec) != SWITCH_STATUS_SUCCESS) {
return SWITCH_STATUS_FALSE;
}
} }
if (context->change_bandwidth) { if (context->change_bandwidth) {
context->codec_settings.video.bandwidth = context->change_bandwidth; context->codec_settings.video.bandwidth = context->change_bandwidth;
context->change_bandwidth = 0; context->change_bandwidth = 0;
init_encoder(codec); if (init_encoder(codec) != SWITCH_STATUS_SUCCESS) {
return SWITCH_STATUS_FALSE;
}
} }
now = switch_time_now(); now = switch_time_now();
@ -709,7 +823,7 @@ static switch_status_t switch_vpx_encode(switch_codec_t *codec, switch_frame_t *
if ((err = vpx_codec_encode(&context->encoder, if ((err = vpx_codec_encode(&context->encoder,
(vpx_image_t *) frame->img, (vpx_image_t *) frame->img,
pts, pts,
dur, dur,
vpx_flags, vpx_flags,
VPX_DL_REALTIME)) != VPX_CODEC_OK) { VPX_DL_REALTIME)) != VPX_CODEC_OK) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "VPX encode error %d:%s:%s\n", switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "VPX encode error %d:%s:%s\n",
@ -814,27 +928,92 @@ static switch_status_t buffer_vp8_packets(vpx_context_t *context, switch_frame_t
return SWITCH_STATUS_SUCCESS; return SWITCH_STATUS_SUCCESS;
} }
// https://tools.ietf.org/id/draft-ietf-payload-vp9-01.txt
static switch_status_t buffer_vp9_packets(vpx_context_t *context, switch_frame_t *frame) static switch_status_t buffer_vp9_packets(vpx_context_t *context, switch_frame_t *frame)
{ {
uint8_t *data = (uint8_t *)frame->data; uint8_t *data = (uint8_t *)frame->data;
uint8_t *vp9 = (uint8_t *)frame->data; uint8_t *vp9 = (uint8_t *)frame->data;
vp9_payload_descriptor_t *desc = (vp9_payload_descriptor_t *)vp9;
int len = 0; int len = 0;
// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%02x %02x %02x %02x %d %d\n", *data, *(data+1), *(data+2), *(data+3), frame->m, frame->datalen); // switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%02x %02x %02x %02x m=%d start=%d end=%d len=%d\n", *data, *(data+1), *(data+2), *(data+3), frame->m, desc->start, desc->end, frame->datalen);
if (switch_buffer_inuse(context->vpx_packet_buffer)) { // middle packet vp9++;
if (IS_VP9_START_PKT(*vp9)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "got invalid vp9 packet, packet loss? resetting buffer\n"); if (desc->is_flexible) {
switch_buffer_zero(context->vpx_packet_buffer); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "VP9 Flexiable mode is not supported yet\n");
switch_buffer_zero(context->vpx_packet_buffer);
goto end;
}
if (desc->have_pid) {
uint16_t pid = 0;
pid = *vp9 & 0x7f;
if (*vp9 & 0x80) {
vp9++;
pid = (pid << 8) + *vp9;
} }
} else { // start packet
if (!IS_VP9_START_PKT(*vp9)) { vp9++;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "got invalid vp9 packet, packet loss? waiting for a start packet\n"); // switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "have pid: %d start=%d end=%d\n", pid, desc->start, desc->end);
goto end; }
if (desc->have_layer_ind) {
vp9_layer_t *layer = (vp9_layer_t *)vp9;
vp9 += 2;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "have layer idx: %d\n", layer->s);
}
if (desc->have_ss) {
vp9_ss_t *ss = (vp9_ss_t *)(vp9++);
context->got_key_frame = 1;
context->got_start_frame = 1;
// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "have ss: %02x n_s: %d y:%d g:%d\n", *(uint8_t *)ss, ss->n_s, ss->y, ss->g);
if (ss->y) {
int i;
for (i=0; i<=ss->n_s; i++) {
int width = ntohs(*(uint16_t *)vp9);
int height = ntohs(*(uint16_t *)(vp9 + 2));
vp9 += 4;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "SS: %d %dx%d\n", i, width, height);
}
}
if (ss->g) {
int i;
uint8_t ng = *vp9++;
for (i = 0; ng > 0 && i < ng; i++) {
vp9_n_g_t *n_g = (vp9_n_g_t *)(vp9++);
vp9 += n_g->r;
}
} }
} }
vp9 = data + 1; if (vp9 - data >= frame->datalen) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid VP9 Packet\n");
switch_buffer_zero(context->vpx_packet_buffer);
goto end;
}
if (switch_buffer_inuse(context->vpx_packet_buffer)) { // middle packet
if (desc->start) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "got invalid vp9 packet, packet loss? resetting buffer\n");
switch_buffer_zero(context->vpx_packet_buffer);
}
} else { // start packet
if (!desc->start) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "got invalid vp9 packet, packet loss? waiting for a start packet\n");
goto end;
}
}
len = frame->datalen - (vp9 - data); len = frame->datalen - (vp9 - data);
switch_buffer_write(context->vpx_packet_buffer, vp9, len); switch_buffer_write(context->vpx_packet_buffer, vp9, len);
@ -860,7 +1039,6 @@ static switch_status_t switch_vpx_decode(switch_codec_t *codec, switch_frame_t *
is_keyframe = IS_VP8_KEY_FRAME((uint8_t *)frame->data); is_keyframe = IS_VP8_KEY_FRAME((uint8_t *)frame->data);
} }
if (context->got_key_frame <= 0) { if (context->got_key_frame <= 0) {
context->no_key_frame++; context->no_key_frame++;
//switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "no keyframe, %d\n", context->no_key_frame); //switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "no keyframe, %d\n", context->no_key_frame);
@ -870,7 +1048,7 @@ static switch_status_t switch_vpx_decode(switch_codec_t *codec, switch_frame_t *
} }
} }
} }
// if (is_keyframe) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "got key %d\n", is_keyframe); // if (is_keyframe) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "got key %d\n", is_keyframe);
if (context->need_decoder_reset != 0) { if (context->need_decoder_reset != 0) {
@ -927,7 +1105,7 @@ static switch_status_t switch_vpx_decode(switch_codec_t *codec, switch_frame_t *
switch_goto_status(SWITCH_STATUS_SUCCESS, end); switch_goto_status(SWITCH_STATUS_SUCCESS, end);
} }
//printf("READ buf:%ld got_key:%d st:%d m:%d\n", switch_buffer_inuse(context->vpx_packet_buffer), context->got_key_frame, status, frame->m); // switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "====READ buf:%ld got_key:%d st:%d m:%d\n", switch_buffer_inuse(context->vpx_packet_buffer), context->got_key_frame, status, frame->m);
len = switch_buffer_inuse(context->vpx_packet_buffer); len = switch_buffer_inuse(context->vpx_packet_buffer);
@ -961,6 +1139,7 @@ static switch_status_t switch_vpx_decode(switch_codec_t *codec, switch_frame_t *
frame->img = NULL; frame->img = NULL;
} else { } else {
frame->img = (switch_image_t *) vpx_codec_get_frame(decoder, &context->dec_iter); frame->img = (switch_image_t *) vpx_codec_get_frame(decoder, &context->dec_iter);
// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%dx%d\n", frame->img->d_w, frame->img->d_h);
} }
switch_buffer_zero(context->vpx_packet_buffer); switch_buffer_zero(context->vpx_packet_buffer);