diff --git a/src/mod/applications/mod_av/avcodec.c b/src/mod/applications/mod_av/avcodec.c index b4eaeadd2e..94cc9b36bf 100644 --- a/src/mod/applications/mod_av/avcodec.c +++ b/src/mod/applications/mod_av/avcodec.c @@ -399,6 +399,7 @@ typedef struct h264_codec_context_s { enum AVCodecID av_codec_id; uint16_t last_seq; // last received frame->seq int hw_encoder; + switch_packetizer_t *packetizer; } h264_codec_context_t; #ifndef AV_INPUT_BUFFER_PADDING_SIZE @@ -1088,64 +1089,6 @@ static switch_status_t consume_h263p_bitstream(h264_codec_context_t *context, sw return SWITCH_STATUS_MORE_DATA; } -static switch_status_t consume_h264_bitstream(h264_codec_context_t *context, switch_frame_t *frame) -{ - AVPacket *pkt = &context->encoder_avpacket; - our_h264_nalu_t *nalu = &context->nalus[context->nalu_current_index]; - uint8_t nalu_hdr = *(uint8_t *)(nalu->start); - uint8_t nalu_type = nalu_hdr & 0x1f; - uint8_t nri = nalu_hdr & 0x60; - int left = nalu->len - (nalu->eat - nalu->start); - uint8_t *p = frame->data; - uint8_t start = nalu->start == nalu->eat ? 0x80 : 0; - int n = nalu->len / SLICE_SIZE; - int slice_size = nalu->len / (n + 1) + 1 + 2; - - if (nalu->len <= SLICE_SIZE) { - memcpy(frame->data, nalu->start, nalu->len); - frame->datalen = nalu->len; - context->nalu_current_index++; - - if (context->nalus[context->nalu_current_index].len) { - frame->m = 0; - return SWITCH_STATUS_MORE_DATA; - } - - if (pkt->size > 0) av_packet_unref(pkt); - - switch_clear_flag(frame, SFF_CNG); - frame->m = 1; - - return SWITCH_STATUS_SUCCESS; - } - - if (left <= (slice_size - 2)) { - p[0] = nri | 28; // FU-A - p[1] = 0x40 | nalu_type; - memcpy(p+2, nalu->eat, left); - nalu->eat += left; - frame->datalen = left + 2; - context->nalu_current_index++; - - if (!context->nalus[context->nalu_current_index].len) { - if (pkt->size > 0) av_packet_unref(pkt); - frame->m = 1; - return SWITCH_STATUS_SUCCESS; - } - - return SWITCH_STATUS_MORE_DATA; - } - - p[0] = nri | 28; // FU-A - p[1] = start | nalu_type; - if (start) nalu->eat++; - memcpy(p+2, nalu->eat, slice_size - 2); - nalu->eat += (slice_size - 2); - frame->datalen = slice_size; - frame->m = 0; - return SWITCH_STATUS_MORE_DATA; -} - static switch_status_t consume_nalu(h264_codec_context_t *context, switch_frame_t *frame) { AVPacket *pkt = &context->encoder_avpacket; @@ -1154,8 +1097,12 @@ static switch_status_t consume_nalu(h264_codec_context_t *context, switch_frame_ if (!nalu->len) { frame->datalen = 0; frame->m = 0; - if (pkt->size > 0) av_packet_unref(pkt); + if (pkt->size > 0) { + av_packet_unref(pkt); + } + context->nalu_current_index = 0; + return SWITCH_STATUS_NOTFOUND; } @@ -1167,7 +1114,9 @@ static switch_status_t consume_nalu(h264_codec_context_t *context, switch_frame_ return consume_h263p_bitstream(context, frame); } - return consume_h264_bitstream(context, frame); + switch_assert(0); + + return SWITCH_STATUS_FALSE; } static void set_h264_private_data(h264_codec_context_t *context, avcodec_profile_t *profile) @@ -1436,6 +1385,14 @@ static switch_status_t switch_h264_init(switch_codec_t *codec, switch_codec_flag } } + switch (context->av_codec_id) { + case AV_CODEC_ID_H264: + context->packetizer = switch_packetizer_create(SPT_H264_BITSTREAM, SLICE_SIZE); + break; + default: + break; + } + switch_buffer_create_dynamic(&(context->nalu_buffer), H264_NALU_BUFFER_SIZE, H264_NALU_BUFFER_SIZE * 8, 0); codec->private_info = context; @@ -1480,6 +1437,16 @@ static switch_status_t switch_h264_encode(switch_codec_t *codec, switch_frame_t } if (frame->flags & SFF_SAME_IMAGE) { + if (context->packetizer) { + switch_status_t status = switch_packetizer_read(context->packetizer, frame); + + if (status == SWITCH_STATUS_SUCCESS && pkt->size > 0) { + av_packet_unref(pkt); + } + + return status; + } + // read from nalu buffer return consume_nalu(context, frame); } @@ -1511,7 +1478,9 @@ static switch_status_t switch_h264_encode(switch_codec_t *codec, switch_frame_t switch_set_flag(frame, SFF_WAIT_KEY_FRAME); } +GCC_DIAG_OFF(deprecated-declarations) av_init_packet(pkt); +GCC_DIAG_ON(deprecated-declarations) pkt->data = NULL; // packet data will be allocated by the encoder pkt->size = 0; @@ -1596,8 +1565,7 @@ GCC_DIAG_ON(deprecated-declarations) // process: if (*got_output) { - const uint8_t *p = pkt->data; - int i = 0; + switch_status_t status = SWITCH_STATUS_SUCCESS; *got_output = 0; @@ -1626,38 +1594,22 @@ GCC_DIAG_ON(deprecated-declarations) "Encoded frame %" SWITCH_INT64_T_FMT " (size=%5d) nalu_type=0x%x %d\n", context->pts, pkt->size, *((uint8_t *)pkt->data +4), *got_output); } - /* split into nalus */ - memset(context->nalus, 0, sizeof(context->nalus)); - while ((p = fs_avc_find_startcode(p, pkt->data+pkt->size)) < (pkt->data + pkt->size)) { - if (!context->nalus[i].start) { - while (!(*p++)) ; /* eat the sync bytes, what ever 0 0 1 or 0 0 0 1 */ - context->nalus[i].start = p; - context->nalus[i].eat = p; + status = switch_packetizer_feed(context->packetizer, pkt->data, pkt->size); + if (status != SWITCH_STATUS_SUCCESS) { + if (pkt->size > 0) { + av_packet_unref(pkt); + } - if ((*p & 0x1f) == 7) { // Got Keyframe - // prevent to generate key frame too frequently - context->last_keyframe_request = switch_time_now(); - if (mod_av_globals.debug) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "KEY FRAME GENERATED\n"); - } - } - } else { - context->nalus[i].len = p - context->nalus[i].start; - while (!(*p++)) ; /* eat the sync bytes, what ever 0 0 1 or 0 0 0 1 */ - i++; - context->nalus[i].start = p; - context->nalus[i].eat = p; - } - if (i >= MAX_NALUS - 2) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "TOO MANY SLICES!\n"); - break; - } + return status; } - context->nalus[i].len = p - context->nalus[i].start; - context->nalu_current_index = 0; - return consume_nalu(context, frame); + status = switch_packetizer_read(context->packetizer, frame); + if (status == SWITCH_STATUS_SUCCESS && pkt->size > 0) { + av_packet_unref(pkt); + } + + return status; } error: @@ -1708,7 +1660,9 @@ static switch_status_t switch_h264_decode(switch_codec_t *codec, switch_frame_t int decoded_len; if (size > 0) { +GCC_DIAG_OFF(deprecated-declarations) av_init_packet(&pkt); +GCC_DIAG_ON(deprecated-declarations) switch_buffer_zero_fill(context->nalu_buffer, AV_INPUT_BUFFER_PADDING_SIZE); switch_buffer_peek_zerocopy(context->nalu_buffer, (const void **)&pkt.data); pkt.size = size; @@ -1825,6 +1779,10 @@ static switch_status_t switch_h264_destroy(switch_codec_t *codec) av_free(context->encoder_ctx); } + if (context->packetizer) { + switch_packetizer_close(&context->packetizer); + } + if (context->encoder_avframe) { av_frame_free(&context->encoder_avframe); } diff --git a/src/mod/applications/mod_av/avformat.c b/src/mod/applications/mod_av/avformat.c index d52e141b6b..d17f4eac39 100644 --- a/src/mod/applications/mod_av/avformat.c +++ b/src/mod/applications/mod_av/avformat.c @@ -877,7 +877,9 @@ static void *SWITCH_THREAD_FUNC video_thread_run(switch_thread_t *thread, void * context->eh.in_callback = 1; +GCC_DIAG_OFF(deprecated-declarations) av_init_packet(&pkt); +GCC_DIAG_ON(deprecated-declarations) if (context->eh.video_st->frame) { ret = av_frame_make_writable(context->eh.video_st->frame); @@ -971,7 +973,9 @@ GCC_DIAG_ON(deprecated-declarations) int got_packet = 0; int ret = 0; +GCC_DIAG_OFF(deprecated-declarations) av_init_packet(&pkt); +GCC_DIAG_ON(deprecated-declarations) GCC_DIAG_OFF(deprecated-declarations) ret = avcodec_encode_video2(context->eh.video_st->st->codec, &pkt, NULL, &got_packet); @@ -1427,7 +1431,9 @@ GCC_DIAG_ON(deprecated-declarations) +GCC_DIAG_OFF(deprecated-declarations) av_init_packet(&pkt); +GCC_DIAG_ON(deprecated-declarations) pkt.data = NULL; pkt.size = 0; @@ -1464,7 +1470,9 @@ GCC_DIAG_ON(deprecated-declarations) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "size = %u %x %x %x %x %x %x\n", pkt.size, *p, *(p+1), *(p+2), *(p+3), *(p+4), *(p+5)); } +GCC_DIAG_OFF(deprecated-declarations) av_init_packet(new_pkt); +GCC_DIAG_ON(deprecated-declarations) av_packet_ref(new_pkt, &pkt); status = switch_queue_push(context->video_pkt_queue, new_pkt); // switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "size = %4u flag=%x pts=%" SWITCH_INT64_T_FMT " dts=%" SWITCH_INT64_T_FMT "\n", pkt.size, pkt.flags, pkt.pts, pkt.dts); @@ -2102,8 +2110,10 @@ GCC_DIAG_ON(deprecated-declarations) int j = 0, ret = -1, audio_stream_count = 1; AVFrame *use_frame = NULL; +GCC_DIAG_OFF(deprecated-declarations) av_init_packet(&pkt[0]); av_init_packet(&pkt[1]); +GCC_DIAG_ON(deprecated-declarations) if (context->audio_st[1].active) { switch_size_t len = 0; diff --git a/src/switch_packetizer.c b/src/switch_packetizer.c index 626e85ba8e..c9cdcbf3e7 100644 --- a/src/switch_packetizer.c +++ b/src/switch_packetizer.c @@ -265,7 +265,7 @@ SWITCH_DECLARE(switch_status_t) switch_packetizer_feed(switch_packetizer_t *pack context->nalus[i].eat = p; } else { context->nalus[i].len = p - context->nalus[i].start; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "#%d %x len=%u\n", i, *context->nalus[i].start, context->nalus[i].len); + //switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "#%d %x len=%u\n", i, *context->nalus[i].start, context->nalus[i].len); while (!(*p++)) ; /* eat the sync bytes, what ever 0 0 1 or 0 0 0 1 */ i++; context->nalus[i].start = p; @@ -307,8 +307,8 @@ SWITCH_DECLARE(switch_status_t) switch_packetizer_read(switch_packetizer_t *pack nri = nalu_hdr & 0x60; if (real_slice_size > slice_size) real_slice_size = slice_size; - if (frame->buflen < slice_size) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "frame buffer too small %u < %u\n", frame->buflen, slice_size); + if (frame->datalen < slice_size) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "frame buffer too small %u < %u\n", frame->datalen, slice_size); return SWITCH_STATUS_FALSE; } diff --git a/tests/unit/switch_packetizer.c b/tests/unit/switch_packetizer.c index 242ca6ae33..006af5a74b 100644 --- a/tests/unit/switch_packetizer.c +++ b/tests/unit/switch_packetizer.c @@ -52,6 +52,7 @@ FST_CORE_BEGIN("conf") frame.data = data; frame.buflen = SWITCH_RECOMMENDED_BUFFER_SIZE; + frame.datalen = SWITCH_RECOMMENDED_BUFFER_SIZE; switch_set_flag(&frame, SFF_ENCODED); status = switch_packetizer_feed(packetizer, h264data, sizeof(h264data)); @@ -94,6 +95,7 @@ FST_CORE_BEGIN("conf") frame.data = data; frame.buflen = SWITCH_RECOMMENDED_BUFFER_SIZE; + frame.datalen = SWITCH_RECOMMENDED_BUFFER_SIZE; switch_set_flag(&frame, SFF_ENCODED); status = switch_packetizer_feed(packetizer, h264data, sizeof(h264data)); @@ -138,6 +140,7 @@ FST_CORE_BEGIN("conf") // 1 fps 3 bytes 1pps 3 bytes frame.data = data; frame.buflen = SWITCH_RECOMMENDED_BUFFER_SIZE; + frame.datalen = SWITCH_RECOMMENDED_BUFFER_SIZE; switch_set_flag(&frame, SFF_ENCODED); status = switch_packetizer_feed_extradata(packetizer, extradata, sizeof(extradata)); @@ -210,6 +213,7 @@ FST_CORE_BEGIN("conf") frame.data = data; frame.buflen = SWITCH_RECOMMENDED_BUFFER_SIZE; + frame.datalen = SWITCH_RECOMMENDED_BUFFER_SIZE; switch_set_flag(&frame, SFF_ENCODED); status = switch_packetizer_feed(packetizer, h264data, sizeof(h264data));