]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
FS-7519: refactor and the av code should work now use it as default, bandwidth might...
authorSeven Du <dujinfang@gmail.com>
Thu, 21 May 2015 18:38:17 +0000 (02:38 +0800)
committerMichael Jerris <mike@jerris.com>
Thu, 28 May 2015 17:47:33 +0000 (12:47 -0500)
src/mod/codecs/mod_avcodec/mod_avcodec.c

index 9496e5f9adbdd1dd645b7ba4ebd2bfc5f9b10311..45c8d00da851aac368bb652f689b5f18028951aa 100644 (file)
@@ -36,7 +36,7 @@
 #include <libavutil/imgutils.h>
 
 /* use libx264 by default, comment out to use the ffmpeg/avcodec wrapper */
-#define H264_CODEC_USE_LIBX264
+// #define H264_CODEC_USE_LIBX264
 
 #define SLICE_SIZE SWITCH_DEFAULT_VIDEO_SIZE
 
@@ -146,7 +146,6 @@ typedef struct h264_codec_context_s {
        x264_nal_t *x264_nals;
        int x264_nal_count;
        int cur_nalu_index;
-
 #endif
 
 } h264_codec_context_t;
@@ -269,7 +268,7 @@ static switch_status_t nalu_slice(h264_codec_context_t *context, switch_frame_t
 
        switch_assert(nalu_len > 0);
 
-       // if ((*buffer & 0x1f) == 7) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Got SPS\n");
+       // if ((*buffer & 0x1f) == 7) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Got SPS | %02x %02x %02x\n", *(buffer+1), *(buffer+2), *(buffer+3));
 
        memcpy(frame->data, buffer, nalu_len);
        frame->datalen = nalu_len;
@@ -365,11 +364,11 @@ static switch_status_t consume_nalu(h264_codec_context_t *context, switch_frame_
 
        if (!nalu->start) {
                frame->datalen = 0;
-               frame->m = 1;
+               frame->m = 0;
                if (context->encoder_avpacket.size > 0) av_free_packet(&context->encoder_avpacket);
                if (context->encoder_avframe->data) av_freep(&context->encoder_avframe->data[0]);
                context->nalu_current_index = 0;
-               return SWITCH_STATUS_SUCCESS;
+               return SWITCH_STATUS_NOTFOUND;
        }
 
        assert(nalu->len);
@@ -395,7 +394,7 @@ static switch_status_t consume_nalu(h264_codec_context_t *context, switch_frame_
                int left = nalu->len - (nalu->eat - nalu->start);
                uint8_t *p = frame->data;
 
-               if (left <= (1400 - 2)) {
+               if (left <= (SLICE_SIZE - 2)) {
                        p[0] = nri | 28; // FU-A
                        p[1] = 0x40 | nalu_type;
                        memcpy(p+2, nalu->eat, left);
@@ -410,9 +409,9 @@ static switch_status_t consume_nalu(h264_codec_context_t *context, switch_frame_
                        p[0] = nri | 28; // FU-A
                        p[1] = start | nalu_type;
                        if (start) nalu->eat++;
-                       memcpy(p+2, nalu->eat, 1400 - 2);
-                       nalu->eat += (1400 - 2);
-                       frame->datalen = 1400;
+                       memcpy(p+2, nalu->eat, SLICE_SIZE - 2);
+                       nalu->eat += (SLICE_SIZE - 2);
+                       frame->datalen = SLICE_SIZE;
                        return SWITCH_STATUS_MORE_DATA;
                }
        }
@@ -428,26 +427,60 @@ static switch_status_t open_encoder(h264_codec_context_t *context, uint32_t widt
                return SWITCH_STATUS_FALSE;
        }
 
-       if (!context->encoder_ctx) context->encoder_ctx = avcodec_alloc_context3(context->encoder);
+       if (context->encoder_ctx) {
+               if (avcodec_is_open(context->encoder_ctx)) {
+                       avcodec_close(context->encoder_ctx);
+               }
+               av_free(context->encoder_ctx);
+               context->encoder_ctx = NULL;
+       }
+
+       context->encoder_ctx = avcodec_alloc_context3(context->encoder);
 
        if (!context->encoder_ctx) {
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not allocate video encoder context\n");
                return SWITCH_STATUS_FALSE;
        }
 
-       context->encoder_ctx->bit_rate = 400000;
+       if (width && height) {
+               context->codec_settings.video.width = width;
+               context->codec_settings.video.height = height;
+       }
+
+       if (!context->codec_settings.video.width) {
+               context->codec_settings.video.width = 1280;
+       }
+
+       if (!context->codec_settings.video.height) {
+               context->codec_settings.video.height = 720;
+       }
+
+       if (context->codec_settings.video.bandwidth) {
+               context->bandwidth = context->codec_settings.video.bandwidth;
+       } else {
+               context->bandwidth = switch_calc_bitrate(context->codec_settings.video.width, context->codec_settings.video.height, 0, 0);
+       }
+
+       if (context->bandwidth > 5120) {
+               context->bandwidth = 5120;
+       }
+
+       context->encoder_ctx->bit_rate = context->bandwidth * 1024;
        context->encoder_ctx->width = width;
        context->encoder_ctx->height = height;
        /* frames per second */
-       context->encoder_ctx->time_base = (AVRational){1, 90000};
+       context->encoder_ctx->time_base = (AVRational){1, FPS};
        context->encoder_ctx->gop_size = FPS * 3; /* emit one intra frame every 3 seconds */
        context->encoder_ctx->max_b_frames = 0;
        context->encoder_ctx->pix_fmt = AV_PIX_FMT_YUV420P;
        context->encoder_ctx->thread_count = 1; // switch_core_cpu_count();
        context->encoder_ctx->rtp_payload_size = SLICE_SIZE;
-       av_opt_set(context->encoder_ctx->priv_data, "preset", "fast", 0);
-
-       if (avcodec_is_open(context->encoder_ctx)) avcodec_close(context->encoder_ctx);
+       context->encoder_ctx->profile = 66;
+       context->encoder_ctx->level = 31;
+       av_opt_set(context->encoder_ctx->priv_data, "preset", "veryfast", 0);
+       av_opt_set(context->encoder_ctx->priv_data, "tune", "animation+zerolatency", 0);
+       av_opt_set(context->encoder_ctx->priv_data, "profile", "baseline", 0);
+       // av_opt_set_int(context->encoder_ctx->priv_data, "slice-max-size", SLICE_SIZE, 0);
 
        if (avcodec_open2(context->encoder_ctx, context->encoder, NULL) < 0) {
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not open codec\n");
@@ -481,7 +514,6 @@ static switch_status_t switch_h264_init(switch_codec_t *codec, switch_codec_flag
                        context->codec_settings = *codec_settings;
                }
 
-
                if (decoding) {
                        context->decoder = avcodec_find_decoder(AV_CODEC_ID_H264);
 
@@ -543,7 +575,7 @@ static switch_status_t switch_h264_encode(switch_codec_t *codec, switch_frame_t
        AVCodecContext *avctx = context->encoder_ctx;
        int ret;
        int *got_output = &context->got_encoded_output;
-       AVFrame *avframe;
+       AVFrame *avframe = NULL;
        AVPacket *pkt = &context->encoder_avpacket;
        uint32_t width = 0;
        uint32_t height = 0;
@@ -576,31 +608,51 @@ static switch_status_t switch_h264_encode(switch_codec_t *codec, switch_frame_t
                if (open_encoder(context, width, height) != SWITCH_STATUS_SUCCESS) {
                        goto error;
                }
+               avctx = context->encoder_ctx;
+       }
+
+       if (context->change_bandwidth) {
+               context->codec_settings.video.bandwidth = context->change_bandwidth;
+               context->change_bandwidth = 0;
+               if (open_encoder(context, width, height) != SWITCH_STATUS_SUCCESS) {
+                       goto error;
+               }
+               avctx = context->encoder_ctx;
+               switch_set_flag(frame, SFF_WAIT_KEY_FRAME);
        }
 
        av_init_packet(pkt);
        pkt->data = NULL;      // packet data will be allocated by the encoder
        pkt->size = 0;
 
-       if (!context->encoder_avframe) context->encoder_avframe = av_frame_alloc();//avcodec_alloc_frame();
-
        avframe = context->encoder_avframe;
 
-       if (!avframe) {
-               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error allocate frame!\n");
-               goto error;
+       if (avframe) {
+               if (avframe->width != width || avframe->height != height) {
+                       av_frame_free(&avframe);
+               }
        }
 
-       avframe->format = avctx->pix_fmt;
-       avframe->width  = avctx->width;
-       avframe->height = avctx->height;
+       if (!avframe) {
+               avframe = av_frame_alloc();
+               context->encoder_avframe = avframe;
 
-       /* the image can be allocated by any means and av_image_alloc() is
-        * just the most convenient way if av_malloc() is to be used */
-       ret = av_image_alloc(avframe->data, avframe->linesize, avctx->width, avctx->height, avctx->pix_fmt, 32);
-       if (ret < 0) {
-               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not allocate raw picture buffer\n");
-               goto error;
+               if (!avframe) {
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error allocate frame!\n");
+                       goto error;
+               }
+
+               avframe->format = avctx->pix_fmt;
+               avframe->width  = avctx->width;
+               avframe->height = avctx->height;
+
+               ret = av_frame_get_buffer(avframe, 32);
+
+               if (ret < 0) {
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not allocate raw picture buffer\n");
+                       av_frame_free(&context->encoder_avframe);
+                       goto error;
+               }
        }
 
        if (*got_output) { // Could be more delayed frames
@@ -611,7 +663,7 @@ static switch_status_t switch_h264_encode(switch_codec_t *codec, switch_frame_t
                }
 
                if (*got_output) {
-                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "Encoded frame %lu (size=%5d) nalu_type=0x%x %d\n", context->pts, pkt->size, *((uint8_t *)pkt->data +4), *got_output);
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "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);
                        goto process;
                }
        }
@@ -620,6 +672,12 @@ static switch_status_t switch_h264_encode(switch_codec_t *codec, switch_frame_t
 
        avframe->pts = context->pts++;
 
+       if (context->need_key_frame) {
+               // switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "NEED Refresh\n");
+               // av_opt_set_int(context->encoder_ctx->priv_data, "intra-refresh", 1, 0);
+               avframe->pict_type = AV_PICTURE_TYPE_I;
+       }
+
        /* encode the image */
        ret = avcodec_encode_video2(avctx, pkt, avframe, got_output);
 
@@ -628,13 +686,18 @@ static switch_status_t switch_h264_encode(switch_codec_t *codec, switch_frame_t
                goto error;
        }
 
+       if (context->need_key_frame) {
+               avframe->pict_type = 0;
+               context->need_key_frame = 0;
+       }
+
 process:
 
        if (*got_output) {
                const uint8_t *p = pkt->data;
                int i = 0;
 
-               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "Encoded frame %lu (size=%5d) nalu_type=0x%x %d\n", context->pts, pkt->size, *((uint8_t *)pkt->data +4), *got_output);
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "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));
@@ -659,11 +722,6 @@ process:
                return consume_nalu(context, frame);
        }
 
-       if (context->encoder_avframe) { //quick code to avoice internal refs
-               av_frame_free(&context->encoder_avframe);
-               context->encoder_avframe = NULL;
-       }
-
 error:
        frame->datalen = 0;
        return SWITCH_STATUS_FALSE;