This source file includes following definitions.
- build_dict
- dc_video_encoder_open
- dc_video_encoder_encode
- dc_video_encoder_close
#include "video_encoder.h"
#include "libavutil/opt.h"
#include "libavdevice/avdevice.h"
#if (defined(WIN32) || defined(_WIN32_WCE)) && !defined(__GNUC__)
#define _TOSTR(_val) #_val
#define TOSTR(_val) _TOSTR(_val)
#endif
void build_dict(void *priv_data, const char *options) {
char *opt = gf_strdup(options);
char *tok = strtok(opt, "=");
char *tokval = NULL;
while (tok && (tokval=strtok(NULL, " "))) {
if (av_opt_set(priv_data, tok, tokval, 0) < 0)
GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Unknown custom option \"%s\" with value \"%s\" in %s\n", tok, tokval, options));
tok = strtok(NULL, "=");
}
gf_free(opt);
}
int dc_video_encoder_open(VideoOutputFile *video_output_file, VideoDataConf *video_data_conf, Bool use_source_timing, AVRational sar)
{
video_output_file->vbuf_size = 9 * video_data_conf->width * video_data_conf->height + 10000;
video_output_file->vbuf = (uint8_t *) av_malloc(video_output_file->vbuf_size);
video_output_file->video_data_conf = video_data_conf;
video_output_file->codec = avcodec_find_encoder_by_name(video_data_conf->codec);
if (video_output_file->codec == NULL) {
GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Output video codec %s not found\n", video_data_conf->codec));
return -1;
}
video_output_file->codec_ctx = avcodec_alloc_context3(video_output_file->codec);
video_output_file->codec_ctx->codec_id = video_output_file->codec->id;
video_output_file->codec_ctx->codec_type = AVMEDIA_TYPE_VIDEO;
video_output_file->codec_ctx->bit_rate = video_data_conf->bitrate;
video_output_file->codec_ctx->width = video_data_conf->width;
video_output_file->codec_ctx->height = video_data_conf->height;
video_output_file->codec_ctx->sample_aspect_ratio = sar;
video_output_file->codec_ctx->time_base.num = 1;
video_output_file->codec_ctx->time_base.den = video_output_file->gop_size ? video_output_file->gop_size : video_data_conf->framerate;
video_output_file->use_source_timing = use_source_timing;
if (use_source_timing) {
video_output_file->codec_ctx->time_base.den = video_data_conf->time_base.den;
video_output_file->codec_ctx->time_base.num = video_data_conf->time_base.num * video_data_conf->time_base.den / video_data_conf->framerate;
}
video_output_file->codec_ctx->pix_fmt = PIX_FMT_YUV420P;
video_output_file->codec_ctx->gop_size = video_data_conf->framerate;
video_output_file->codec_ctx->gop_size = video_data_conf->framerate;
if ( strlen(video_data_conf->custom) ) {
build_dict(video_output_file->codec_ctx->priv_data, video_data_conf->custom);
} else if (video_data_conf->low_delay) {
GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("Video Encoder: applying default options (preset=ultrafast tune=zerolatency)\n"));
av_opt_set(video_output_file->codec_ctx->priv_data, "vprofile", "baseline", 0);
av_opt_set(video_output_file->codec_ctx->priv_data, "preset", "ultrafast", 0);
av_opt_set(video_output_file->codec_ctx->priv_data, "tune", "zerolatency", 0);
if (strstr(video_data_conf->codec, "264")) {
av_opt_set(video_output_file->codec_ctx->priv_data, "x264opts", "no-mbtree:sliced-threads:sync-lookahead=0", 0);
}
}
if (video_output_file->gdr) {
av_opt_set_int(video_output_file->codec_ctx->priv_data, "intra-refresh", 1, 0);
av_opt_set_int(video_output_file->codec_ctx->priv_data, "key-int", video_output_file->gdr, 0);
}
video_output_file->codec_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER;
video_output_file->vstream_idx = 0;
if (avcodec_open2(video_output_file->codec_ctx, video_output_file->codec, NULL) < 0) {
GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open output video codec\n"));
return -1;
}
video_output_file->rep_id = video_data_conf->filename;
return 0;
}
int dc_video_encoder_encode(VideoOutputFile *video_output_file, VideoScaledData *video_scaled_data)
{
VideoScaledDataNode *video_data_node;
int ret;
u64 time_spent;
int got_packet = 0;
AVPacket pkt;
AVCodecContext *video_codec_ctx = video_output_file->codec_ctx;
ret = dc_consumer_lock(&video_output_file->consumer, &video_scaled_data->circular_buf);
if (ret < 0) {
GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Video encoder got an end of buffer!\n"));
return -2;
}
if (video_scaled_data->circular_buf.size > 1)
dc_consumer_unlock_previous(&video_output_file->consumer, &video_scaled_data->circular_buf);
video_data_node = (VideoScaledDataNode*)dc_consumer_consume(&video_output_file->consumer, &video_scaled_data->circular_buf);
if (!video_output_file->use_source_timing) {
video_data_node->vframe->pts = video_codec_ctx->frame_number;
}
time_spent = gf_sys_clock_high_res();
av_init_packet(&pkt);
pkt.data = video_output_file->vbuf;
pkt.size = video_output_file->vbuf_size;
pkt.pts = pkt.dts = video_data_node->vframe->pkt_dts = video_data_node->vframe->pkt_pts = video_data_node->vframe->pts;
video_data_node->vframe->pict_type = 0;
video_data_node->vframe->width = video_codec_ctx->width;
video_data_node->vframe->height = video_codec_ctx->height;
video_data_node->vframe->format = video_codec_ctx->pix_fmt;
#ifdef LIBAV_ENCODE_OLD
if (!video_output_file->segment_started)
video_data_node->vframe->pict_type = FF_I_TYPE;
video_output_file->encoded_frame_size = avcodec_encode_video(video_codec_ctx, video_output_file->vbuf, video_output_file->vbuf_size, video_data_node->vframe);
got_packet = video_output_file->encoded_frame_size>=0 ? 1 : 0;
#else
if (!video_output_file->segment_started)
video_data_node->vframe->pict_type = AV_PICTURE_TYPE_I;
video_output_file->encoded_frame_size = avcodec_encode_video2(video_codec_ctx, &pkt, video_data_node->vframe, &got_packet);
#endif
time_spent = gf_sys_clock_high_res() - time_spent;
#ifndef GPAC_USE_LIBAV
if (video_output_file->encoded_frame_size >= 0)
video_output_file->encoded_frame_size = pkt.size;
#else
if (got_packet)
video_output_file->encoded_frame_size = pkt.size;
#endif
if (video_output_file->encoded_frame_size >= 0) {
if (got_packet) {
video_codec_ctx->coded_frame->pts = video_codec_ctx->coded_frame->pkt_pts = pkt.pts;
video_codec_ctx->coded_frame->pkt_dts = pkt.dts;
video_codec_ctx->coded_frame->key_frame = (pkt.flags & AV_PKT_FLAG_KEY) ? 1 : 0;
video_output_file->frame_ntp = video_data_node->frame_ntp;
video_output_file->frame_utc = video_data_node->frame_utc;
}
}
dc_consumer_advance(&video_output_file->consumer);
if (video_scaled_data->circular_buf.size == 1)
dc_consumer_unlock_previous(&video_output_file->consumer, &video_scaled_data->circular_buf);
if (video_output_file->encoded_frame_size < 0) {
GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error occured while encoding video frame.\n"));
return -1;
}
GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DashCast] Video %s Frame TS "LLU" encoded at UTC "LLU" ms in "LLU" us\n", video_output_file->rep_id, video_data_node->vframe->pts, gf_net_get_utc(), time_spent ));
return video_output_file->encoded_frame_size;
}
void dc_video_encoder_close(VideoOutputFile *video_output_file)
{
av_free(video_output_file->vbuf);
avcodec_close(video_output_file->codec_ctx);
av_free(video_output_file->codec_ctx);
}