/* With LOCK */ static gboolean gst_ffmpegauddec_close (GstFFMpegAudDec * ffmpegdec, gboolean reset) { GstFFMpegAudDecClass *oclass; oclass = (GstFFMpegAudDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); GST_LOG_OBJECT (ffmpegdec, "closing libav codec"); gst_caps_replace (&ffmpegdec->last_caps, NULL); gst_buffer_replace (&ffmpegdec->outbuf, NULL); gst_ffmpeg_avcodec_close (ffmpegdec->context); ffmpegdec->opened = FALSE; if (ffmpegdec->context->extradata) { av_free (ffmpegdec->context->extradata); ffmpegdec->context->extradata = NULL; } if (reset) { if (avcodec_get_context_defaults3 (ffmpegdec->context, oclass->in_plugin) < 0) { GST_DEBUG_OBJECT (ffmpegdec, "Failed to set context defaults"); return FALSE; } ffmpegdec->context->opaque = ffmpegdec; } return TRUE; }
/* Add a video output stream. */ static AVStream *add_video_stream(AVFormatContext *oc, enum CodecID codec_id) { AVCodecContext *c; AVStream *st; AVCodec *codec; /* find the video encoder */ codec = avcodec_find_encoder(codec_id); if (!codec) { fprintf(stderr, "codec not found\n"); exit(1); } st = avformat_new_stream(oc, codec); if (!st) { fprintf(stderr, "Could not alloc stream\n"); exit(1); } c = st->codec; /* find the video encoder */ codec = avcodec_find_encoder(codec_id); if (!codec) { fprintf(stderr, "codec not found\n"); exit(1); } avcodec_get_context_defaults3(c, codec); c->codec_id = codec_id; /* Put sample parameters. */ c->bit_rate = 400000; /* Resolution must be a multiple of two. */ c->width = 352; c->height = 288; /* timebase: This is the fundamental unit of time (in seconds) in terms * of which frame timestamps are represented. For fixed-fps content, * timebase should be 1/framerate and timestamp increments should be * identical to 1. */ c->time_base.den = STREAM_FRAME_RATE; c->time_base.num = 1; c->gop_size = 12; /* emit one intra frame every twelve frames at most */ c->pix_fmt = STREAM_PIX_FMT; if (c->codec_id == CODEC_ID_MPEG2VIDEO) { /* just for testing, we also add B frames */ c->max_b_frames = 2; } if (c->codec_id == CODEC_ID_MPEG1VIDEO) { /* Needed to avoid using macroblocks in which some coeffs overflow. * This does not happen with normal video, it just happens here as * the motion of the chroma plane does not match the luma plane. */ c->mb_decision = 2; } /* Some formats want stream headers to be separate. */ if (oc->oformat->flags & AVFMT_GLOBALHEADER) c->flags |= CODEC_FLAG_GLOBAL_HEADER; return st; }
AVStream* Muxer::CreateStream(AVCodec* codec) { Q_ASSERT(!m_started); Q_ASSERT(m_format_context->nb_streams < MUXER_MAX_STREAMS); // create a new stream #if SSR_USE_AVFORMAT_NEW_STREAM AVStream *stream = avformat_new_stream(m_format_context, codec); #else AVStream *stream = av_new_stream(m_format_context, m_format_context->nb_streams); #endif if(stream == NULL) { Logger::LogError("[Muxer::AddStream] " + QObject::tr("Error: Can't create new stream!")); throw LibavException(); } #if !SSR_USE_AVFORMAT_NEW_STREAM if(avcodec_get_context_defaults3(stream->codec, codec) < 0) { Logger::LogError("[Muxer::AddStream] " + QObject::tr("Error: Can't get codec context defaults!")); throw LibavException(); } stream->codec->codec_id = codec->id; stream->codec->codec_type = codec->type; #endif // not sure why this is needed, but it's in the example code and it doesn't work without this if(m_format_context->oformat->flags & AVFMT_GLOBALHEADER) stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER; return stream; }
AVCodecContext *avcodec_alloc_context3(AVCodec *codec) { /* 参数: 1、 返回: 1、 说明: 1、 */ AVCodecContext *avctx= av_malloc(sizeof(AVCodecContext)); if(avctx==NULL) return NULL; if(avcodec_get_context_defaults3(avctx, codec) < 0) { av_free(avctx); return NULL; } return avctx; }
AVStream* Muxer::AddStream(AVCodec* codec, AVCodecContext** codec_context) { assert(!m_started); assert(m_format_context->nb_streams < MUXER_MAX_STREAMS); Logger::LogInfo("[Muxer::AddStream] " + Logger::tr("Using codec %1 (%2).").arg(codec->name).arg(codec->long_name)); // create a new stream #if SSR_USE_AVSTREAM_CODECPAR AVStream *stream = avformat_new_stream(m_format_context, NULL); #elif SSR_USE_AVFORMAT_NEW_STREAM AVStream *stream = avformat_new_stream(m_format_context, codec); #else AVStream *stream = av_new_stream(m_format_context, m_format_context->nb_streams); #endif if(stream == NULL) { Logger::LogError("[Muxer::AddStream] " + Logger::tr("Error: Can't create new stream!")); throw LibavException(); } assert(stream->index == (int) m_format_context->nb_streams - 1); #if SSR_USE_AVSTREAM_CODECPAR *codec_context = avcodec_alloc_context3(codec); if(*codec_context == NULL) { Logger::LogError("[Muxer::AddStream] " + Logger::tr("Error: Can't create new codec context!")); throw LibavException(); } #else assert(stream->codec != NULL); *codec_context = stream->codec; #endif //stream->id = m_format_context->nb_streams - 1; #if !SSR_USE_AVFORMAT_NEW_STREAM // initialize the codec context (only needed for old API) if(avcodec_get_context_defaults3(*codec_context, codec) < 0) { Logger::LogError("[Muxer::AddStream] " + Logger::tr("Error: Can't get codec context defaults!")); throw LibavException(); } (*codec_context)->codec_id = codec->id; (*codec_context)->codec_type = codec->type; #endif // not sure why this is needed, but it's in the example code and it doesn't work without this if(m_format_context->oformat->flags & AVFMT_GLOBALHEADER) (*codec_context)->flags |= CODEC_FLAG_GLOBAL_HEADER; // if the codec is experimental, allow it if(codec->capabilities & CODEC_CAP_EXPERIMENTAL) { Logger::LogWarning("[Muxer::AddStream] " + Logger::tr("Warning: This codec is considered experimental by libav/ffmpeg.")); (*codec_context)->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL; } #if SSR_USE_SIDE_DATA_ONLY_PACKETS && !SSR_USE_SIDE_DATA_ONLY_PACKETS_DEPRECATED // this option was added with the intent to deprecate it again in the next version, // because the ffmpeg/libav devs like deprecating things :) (*codec_context)->side_data_only_packets = 1; #endif return stream; }
static void AddAudioStream() { g_pAStream = avformat_new_stream(g_pContainer, g_pACodec); if(!g_pAStream) { Log("Could not allocate audio stream\n"); return; } g_pAStream->id = 1; g_pAudio = g_pAStream->codec; avcodec_get_context_defaults3(g_pAudio, g_pACodec); g_pAudio->codec_id = g_pACodec->id; // put parameters g_pAudio->sample_fmt = AV_SAMPLE_FMT_S16; g_pAudio->sample_rate = g_Frequency; g_pAudio->channels = g_Channels; // set time base as invers of sample rate g_pAudio->time_base.den = g_pAStream->time_base.den = g_Frequency; g_pAudio->time_base.num = g_pAStream->time_base.num = 1; // set quality g_pAudio->bit_rate = 160000; // for codecs that support variable bitrate use it, it should be better g_pAudio->flags |= AV_CODEC_FLAG_QSCALE; g_pAudio->global_quality = 1*FF_QP2LAMBDA; // some formats want stream headers to be separate if (g_pFormat->flags & AVFMT_GLOBALHEADER) g_pAudio->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; // open it if (avcodec_open2(g_pAudio, g_pACodec, NULL) < 0) { Log("Could not open audio codec %s\n", g_pACodec->long_name); return; } #if LIBAVCODEC_VERSION_MAJOR >= 54 if (g_pACodec->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE) #else if (g_pAudio->frame_size == 0) #endif g_NumSamples = 4096; else g_NumSamples = g_pAudio->frame_size; g_pSamples = (int16_t*)av_malloc(g_NumSamples*g_Channels*sizeof(int16_t)); g_pAFrame = av_frame_alloc(); if (!g_pAFrame) { Log("Could not allocate frame\n"); return; } }
/* Add an output stream. */ static AVStream *add_stream(AVFormatContext *oc, AVCodec **codec, enum AVCodecID codec_id, StreamInfo *sInfo) { AVCodecContext *c; AVStream *st; /* find the encoder */ *codec = avcodec_find_encoder(codec_id); if (!(*codec)) { fprintf(stderr, "Could not find encoder for '%s'\n", avcodec_get_name(codec_id)); exit(1); } st = avformat_new_stream(oc, *codec); if (!st) { fprintf(stderr, "Could not allocate stream\n"); exit(1); } st->id = oc->nb_streams - 1; c = st->codec; switch ((*codec)->type) { case AVMEDIA_TYPE_VIDEO: avcodec_get_context_defaults3(c, *codec); c->codec_id = codec_id; c->bit_rate = sInfo->bitrate; /* Resolution must be a multiple of two. */ c->width = sInfo->width; c->height = sInfo->height; /* timebase: This is the fundamental unit of time (in seconds) in terms * of which frame timestamps are represented. For fixed-fps content, * timebase should be 1/framerate and timestamp increments should be * identical to 1. */ c->time_base.den = sInfo->frame_rate; c->time_base.num = 1; c->gop_size = 12; /* emit one intra frame every twelve frames at most */ c->pix_fmt = sInfo->pix_fmt; c->rc_min_rate = sInfo->bitrate-50; c->rc_max_rate = sInfo->bitrate+50; c->rc_buffer_size = sInfo->bitrate+60; if (c->codec_id == AV_CODEC_ID_MPEG2VIDEO) { /* just for testing, we also add B frames */ //c->max_b_frames = 2; } if (c->codec_id == AV_CODEC_ID_MPEG1VIDEO) { /* Needed to avoid using macroblocks in which some coeffs overflow. * This does not happen with normal video, it just happens here as * the motion of the chroma plane does not match the luma plane. */ c->mb_decision = 2; } break; default: break; } /* Some formats want stream headers to be separate. */ if (oc->oformat->flags & AVFMT_GLOBALHEADER) c->flags |= CODEC_FLAG_GLOBAL_HEADER; return st; }
int janus_pp_h264_create(char *destination) { if(destination == NULL) return -1; /* Setup FFmpeg */ av_register_all(); /* Adjust logging to match the postprocessor's */ av_log_set_level(janus_log_level <= LOG_NONE ? AV_LOG_QUIET : (janus_log_level == LOG_FATAL ? AV_LOG_FATAL : (janus_log_level == LOG_ERR ? AV_LOG_ERROR : (janus_log_level == LOG_WARN ? AV_LOG_WARNING : (janus_log_level == LOG_INFO ? AV_LOG_INFO : (janus_log_level == LOG_VERB ? AV_LOG_VERBOSE : AV_LOG_DEBUG)))))); /* MP4 output */ fctx = avformat_alloc_context(); if(fctx == NULL) { JANUS_LOG(LOG_ERR, "Error allocating context\n"); return -1; } fctx->oformat = av_guess_format("mp4", NULL, NULL); if(fctx->oformat == NULL) { JANUS_LOG(LOG_ERR, "Error guessing format\n"); return -1; } snprintf(fctx->filename, sizeof(fctx->filename), "%s", destination); vStream = avformat_new_stream(fctx, 0); if(vStream == NULL) { JANUS_LOG(LOG_ERR, "Error adding stream\n"); return -1; } #if LIBAVCODEC_VER_AT_LEAST(53, 21) avcodec_get_context_defaults3(vStream->codec, AVMEDIA_TYPE_VIDEO); #else avcodec_get_context_defaults2(vStream->codec, AVMEDIA_TYPE_VIDEO); #endif #if LIBAVCODEC_VER_AT_LEAST(54, 25) vStream->codec->codec_id = AV_CODEC_ID_H264; #else vStream->codec->codec_id = CODEC_ID_H264; #endif vStream->codec->codec_type = AVMEDIA_TYPE_VIDEO; vStream->codec->time_base = (AVRational){1, fps}; vStream->time_base = (AVRational){1, 90000}; vStream->codec->width = max_width; vStream->codec->height = max_height; vStream->codec->pix_fmt = PIX_FMT_YUV420P; //~ if (fctx->flags & AVFMT_GLOBALHEADER) vStream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER; if(avio_open(&fctx->pb, fctx->filename, AVIO_FLAG_WRITE) < 0) { JANUS_LOG(LOG_ERR, "Error opening file for output\n"); return -1; } if(avformat_write_header(fctx, NULL) < 0) { JANUS_LOG(LOG_ERR, "Error writing header\n"); return -1; } return 0; }
void addVideoStream(AVFormatContext *dest){ AVCodecContext *c; AVStream *st; AVCodec *codec; /* find the video encoder */ codec = avcodec_find_encoder(VIDEO_CODEC_ID); if (!codec) { LOGI("add_video_stream codec not found, as expected. No encoding necessary"); } st = avformat_new_stream(dest, codec); if (!st) { LOGE("add_video_stream could not alloc stream"); } videoStreamIndex = st->index; LOGI("addVideoStream at index %d", videoStreamIndex); c = st->codec; avcodec_get_context_defaults3(c, codec); c->codec_id = VIDEO_CODEC_ID; /* Put sample parameters. */ // c->bit_rate = 400000; /* Resolution must be a multiple of two. */ c->width = VIDEO_WIDTH; c->height = VIDEO_HEIGHT; /* timebase: This is the fundamental unit of time (in seconds) in terms * of which frame timestamps are represented. For fixed-fps content, * timebase should be 1/framerate and timestamp increments should be * identical to 1. */ c->time_base.den = 30; c->time_base.num = 1; /* c->gop_size = 12; // emit one intra frame every twelve frames at most */ c->pix_fmt = VIDEO_PIX_FMT; /* Not encoding if(codec_id == CODEC_ID_H264){ av_opt_set(c->priv_data, "preset", "ultrafast", 0); if(crf) av_opt_set_double(c->priv_data, "crf", crf, 0); else av_opt_set_double(c->priv_data, "crf", 24.0, 0); } */ /* Some formats want stream headers to be separate. */ if (dest->oformat->flags & AVFMT_GLOBALHEADER) c->flags |= CODEC_FLAG_GLOBAL_HEADER; }
static void output_init() { int i, err; AVCodec *c[2]; char *guess_fp = "a.flv"; // AVStream *st = ; ofc = avformat_alloc_context(); AVOutputFormat *ofmt = av_guess_format(NULL, guess_fp, NULL); ofc->oformat = ofmt; strcpy(ofc->filename, guess_fp); printf("ofc ok\n"); AVStream *ost[2]; ost[0] = avformat_new_stream(ofc, NULL); //ost[0]->codec->codec_id = ist[0]->codec->codec_id; AVCodecContext *codec[2]; codec[0] = ost[0]->codec; avcodec_get_context_defaults3(codec[0], NULL); codec[0]->codec_id = AV_CODEC_ID_H264; codec[0]->codec_type = AVMEDIA_TYPE_VIDEO; codec[0]->time_base.num = 1; codec[0]->time_base.den = 25; codec[0]->width = 720; codec[0]->height = 360; codec[0]->codec_tag = av_codec_get_tag(ofmt->codec_tag, AV_CODEC_ID_H264); printf("ofc->codec codec[0]=%p ofc->st[0]->codec=%p\n", codec[0], ofc->streams[0]->codec); printf("codec[0].tag=%d\n", codec[0]->codec_tag); err = avio_open2(&ofc->pb, output_filename, AVIO_FLAG_WRITE, NULL, NULL); printf("open2=%d\n", err); printf("write header\n"); printf("ofc.nb_streams=%d\n", ofc->nb_streams); printf("ofc.st[0]=%p\n", ofc->streams[0]); printf("ofc.st[0].codec=%p\n", ofc->streams[0]->codec); printf("ofc.oformat=%p\n", ofc->oformat); printf("ofc.oformat.write_header=%p\n", ofc->oformat->write_header); printf("ofc.oformat.name=%s\n", ofc->oformat->name); printf("ofc.pb=%p\n", ofc->pb); printf("ofc.st[0].avg_frame_rate={%d,%d}\n", ofc->streams[0]->avg_frame_rate.num, ofc->streams[0]->avg_frame_rate.den ); printf("ofc.st[0].codec.timebase={%d,%d}\n", ofc->streams[0]->codec->time_base.num, ofc->streams[0]->codec->time_base.den ); printf("ofc.priv=%p\n", ofc->priv_data); //err = ofc->oformat->write_header(ofc); err = avformat_write_header(ofc, NULL); printf("write_header=%d\n", err); avio_flush(ofc->pb); }
static void dec_open(DecData *d){ AVCodec *codec; int error; codec=avcodec_find_decoder(CODEC_ID_H264); if (codec==NULL) ms_fatal("Could not find H264 decoder in ffmpeg."); avcodec_get_context_defaults3(&d->av_context, NULL); error=avcodec_open2(&d->av_context,codec, NULL); if (error!=0){ ms_fatal("avcodec_open() failed."); } }
AVCodecContext *avcodec_alloc_context3(const AVCodec *codec) { AVCodecContext *avctx= av_malloc(sizeof(AVCodecContext)); if (!avctx) return NULL; if(avcodec_get_context_defaults3(avctx, codec) < 0){ av_free(avctx); return NULL; } return avctx; }
int CamReadThread::EncodeInit() { c= NULL; int yuv420_bytes = 0; m_pRGBFrame = new AVFrame[1]; //RGB帧数据 m_pYUVFrame = new AVFrame[1]; //YUV帧数据 av_register_all(); avcodec_register_all(); avformat_network_init(); fmtctx = avformat_alloc_context(); codec = avcodec_find_encoder(AV_CODEC_ID_H264); if (!codec) { dbgprint("%s(%d),%d CAM Codec not found!\n",DEBUGARGS,CameraID); return -1; } video_st = avformat_new_stream(fmtctx, codec); c = video_st->codec; avcodec_get_context_defaults3(c, codec); if (!c) { dbgprint("%s(%d),%d CAM Could not allocate video codec context!\n",DEBUGARGS,CameraID); return -1; } c->codec_id = AV_CODEC_ID_H264; c->width = m_cols; c->height = m_rows; c->time_base = (AVRational){1,m_fps}; c->gop_size = 10; c->max_b_frames = 1; c->pix_fmt = AV_PIX_FMT_YUV420P; if (avcodec_open2(c, codec, NULL) < 0) { dbgprint("%s(%d),%d CAM Could not open codec!\n",DEBUGARGS,CameraID); return -1; } m_pYUVFrame = av_frame_alloc(); yuv420_bytes = avpicture_get_size( AV_PIX_FMT_YUV420P, m_cols, m_rows); pYUV_buffer = (uint8_t *)av_malloc(yuv420_bytes*sizeof(uint8_t)); m_pYUVFrame->format = c->pix_fmt; m_pYUVFrame->width = c->width; m_pYUVFrame->height = c->height; avpicture_fill((AVPicture*)m_pYUVFrame, pYUV_buffer, AV_PIX_FMT_YUV420P, m_cols, m_rows); scxt = sws_getContext(m_cols, m_rows,AV_PIX_FMT_RGB24, m_cols, m_rows,AV_PIX_FMT_YUV420P, 0, 0, 0, 0); return 0; }
static gboolean gst_ffmpegvidenc_start (GstVideoEncoder * encoder) { GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) encoder; GstFFMpegVidEncClass *oclass = (GstFFMpegVidEncClass *) G_OBJECT_GET_CLASS (ffmpegenc); /* close old session */ if (avcodec_get_context_defaults3 (ffmpegenc->context, oclass->in_plugin) < 0) { GST_DEBUG_OBJECT (ffmpegenc, "Failed to set context defaults"); return FALSE; } return TRUE; }
static gboolean gst_ffmpegaudenc_start (GstAudioEncoder * encoder) { GstFFMpegAudEnc *ffmpegaudenc = (GstFFMpegAudEnc *) encoder; GstFFMpegAudEncClass *oclass = (GstFFMpegAudEncClass *) G_OBJECT_GET_CLASS (ffmpegaudenc); gst_ffmpeg_avcodec_close (ffmpegaudenc->context); if (avcodec_get_context_defaults3 (ffmpegaudenc->context, oclass->in_plugin) < 0) { GST_DEBUG_OBJECT (ffmpegaudenc, "Failed to set context defaults"); return FALSE; } return TRUE; }
AVStream* Muxer::AddStream(AVCodec* codec) { assert(!m_started); assert(m_format_context->nb_streams < MUXER_MAX_STREAMS); Logger::LogInfo("[Muxer::AddStream] " + Logger::tr("Using codec %1 (%2).").arg(codec->name).arg(codec->long_name)); // create a new stream #if SSR_USE_AVFORMAT_NEW_STREAM AVStream *stream = avformat_new_stream(m_format_context, codec); #else AVStream *stream = av_new_stream(m_format_context, m_format_context->nb_streams); #endif if(stream == NULL) { Logger::LogError("[Muxer::AddStream] " + Logger::tr("Error: Can't create new stream!")); throw LibavException(); } assert(stream->index == (int) m_format_context->nb_streams - 1); assert(stream->codec != NULL); //stream->id = m_format_context->nb_streams - 1; #if !SSR_USE_AVFORMAT_NEW_STREAM // initialize the codec context (only needed for old API) if(avcodec_get_context_defaults3(stream->codec, codec) < 0) { Logger::LogError("[Muxer::AddStream] " + Logger::tr("Error: Can't get codec context defaults!")); throw LibavException(); } stream->codec->codec_id = codec->id; stream->codec->codec_type = codec->type; #else //assert(stream->codec->codec_id == codec->id); //assert(stream->codec->codec_type == codec->type); #endif // not sure why this is needed, but it's in the example code and it doesn't work without this if(m_format_context->oformat->flags & AVFMT_GLOBALHEADER) stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER; // if the codec is experimental, allow it if(codec->capabilities & CODEC_CAP_EXPERIMENTAL) { Logger::LogWarning("[Muxer::AddStream] " + Logger::tr("Warning: This codec is considered experimental by libav/ffmpeg.")); stream->codec->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL; } return stream; }
std::shared_ptr<AVStream> add_audio_stream(std::vector<option>& options) { if(output_format_.acodec == CODEC_ID_NONE) return nullptr; auto st = av_new_stream(oc_.get(), 1); if(!st) BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("Could not allocate audio-stream") << boost::errinfo_api_function("av_new_stream")); auto encoder = avcodec_find_encoder(output_format_.acodec); if (!encoder) BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("codec not found")); auto c = st->codec; avcodec_get_context_defaults3(c, encoder); c->codec_id = output_format_.acodec; c->codec_type = AVMEDIA_TYPE_AUDIO; c->sample_rate = 48000; c->channels = channel_layout_.num_channels; c->sample_fmt = SAMPLE_FMT_S16; if(output_format_.vcodec == CODEC_ID_FLV1) c->sample_rate = 44100; if(output_format_.format->flags & AVFMT_GLOBALHEADER) c->flags |= CODEC_FLAG_GLOBAL_HEADER; boost::range::remove_erase_if(options, [&](const option& o) { return ffmpeg::av_opt_set(c, o.name.c_str(), o.value.c_str(), AV_OPT_SEARCH_CHILDREN) > -1; }); THROW_ON_ERROR2(avcodec_open(c, encoder), "[ffmpeg_consumer]"); return std::shared_ptr<AVStream>(st, [](AVStream* st) { LOG_ON_ERROR2(avcodec_close(st->codec), "[ffmpeg_consumer]");; av_freep(&st->codec); av_freep(&st); }); }
static gboolean gst_ffmpegauddec_start (GstAudioDecoder * decoder) { GstFFMpegAudDec *ffmpegdec = (GstFFMpegAudDec *) decoder; GstFFMpegAudDecClass *oclass; oclass = (GstFFMpegAudDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); GST_OBJECT_LOCK (ffmpegdec); gst_ffmpeg_avcodec_close (ffmpegdec->context); if (avcodec_get_context_defaults3 (ffmpegdec->context, oclass->in_plugin) < 0) { GST_DEBUG_OBJECT (ffmpegdec, "Failed to set context defaults"); GST_OBJECT_UNLOCK (ffmpegdec); return FALSE; } ffmpegdec->context->opaque = ffmpegdec; GST_OBJECT_UNLOCK (ffmpegdec); return TRUE; }
void addAudioStream(AVFormatContext *formatContext){ AVCodecContext *codecContext; AVStream *st; AVCodec *codec; /* find the audio encoder */ codec = avcodec_find_encoder(AUDIO_CODEC_ID); if (!codec) { LOGE("add_audio_stream codec not found"); } //LOGI("add_audio_stream found codec_id: %d",codec_id); st = avformat_new_stream(formatContext, codec); if (!st) { LOGE("add_audio_stream could not alloc stream"); } audioStreamIndex = st->index; //st->id = 1; codecContext = st->codec; avcodec_get_context_defaults3(codecContext, codec); codecContext->strict_std_compliance = FF_COMPLIANCE_UNOFFICIAL; // for native aac support /* put sample parameters */ //codecContext->sample_fmt = AV_SAMPLE_FMT_FLT; codecContext->sample_fmt = AUDIO_SAMPLE_FMT; codecContext->time_base.den = 44100; codecContext->time_base.num = 1; //c->bit_rate = bit_rate; codecContext->sample_rate = AUDIO_SAMPLE_RATE; codecContext->channels = AUDIO_CHANNELS; LOGI("addAudioStream sample_rate %d index %d", codecContext->sample_rate, st->index); //LOGI("add_audio_stream parameters: sample_fmt: %d bit_rate: %d sample_rate: %d", codec_audio_sample_fmt, bit_rate, audio_sample_rate); // some formats want stream headers to be separate if (formatContext->oformat->flags & AVFMT_GLOBALHEADER) codecContext->flags |= CODEC_FLAG_GLOBAL_HEADER; }
static int ffserver_set_codec(AVCodecContext *ctx, const char *codec_name, FFServerConfig *config) { int ret; AVCodec *codec = avcodec_find_encoder_by_name(codec_name); if (!codec || codec->type != ctx->codec_type) { report_config_error(config->filename, config->line_num, AV_LOG_ERROR, &config->errors, "Invalid codec name: '%s'\n", codec_name); return 0; } if (ctx->codec_id == AV_CODEC_ID_NONE && !ctx->priv_data) { if ((ret = avcodec_get_context_defaults3(ctx, codec)) < 0) return ret; ctx->codec = codec; } if (ctx->codec_id != codec->id) report_config_error(config->filename, config->line_num, AV_LOG_ERROR, &config->errors, "Inconsistent configuration: trying to set '%s' " "codec option, but '%s' codec is used previously\n", codec_name, avcodec_get_name(ctx->codec_id)); return 0; }
static int bt_play_open(struct voss_backend *pbe, const char *devname, int samplerate, int bufsize, int *pchannels, int *pformat) { struct bt_config *cfg = pbe->arg; int retval; bt_init_cfg(cfg); retval = bt_open(pbe, devname, samplerate, bufsize, pchannels, pformat, cfg, SDP_SERVICE_CLASS_AUDIO_SINK, 1); if (retval != 0) return (retval); /* setup codec */ switch (cfg->codec) { case CODEC_SBC: cfg->handle.sbc_enc = malloc(sizeof(*cfg->handle.sbc_enc)); if (cfg->handle.sbc_enc == NULL) return (-1); memset(cfg->handle.sbc_enc, 0, sizeof(*cfg->handle.sbc_enc)); break; #ifdef HAVE_FFMPEG case CODEC_AAC: av_register_all(); cfg->handle.av.codec = avcodec_find_encoder_by_name("aac"); if (cfg->handle.av.codec == NULL) { DPRINTF("Codec AAC encoder not found\n"); goto av_error_0; } cfg->handle.av.format = avformat_alloc_context(); if (cfg->handle.av.format == NULL) { DPRINTF("Could not allocate format context\n"); goto av_error_0; } cfg->handle.av.format->oformat = av_guess_format("latm", NULL, NULL); if (cfg->handle.av.format->oformat == NULL) { DPRINTF("Could not guess output format\n"); goto av_error_1; } cfg->handle.av.stream = avformat_new_stream( cfg->handle.av.format, cfg->handle.av.codec); if (cfg->handle.av.stream == NULL) { DPRINTF("Could not create new stream\n"); goto av_error_1; } cfg->handle.av.context = cfg->handle.av.stream->codec; if (cfg->handle.av.context == NULL) { DPRINTF("Could not allocate audio context\n"); goto av_error_1; } avcodec_get_context_defaults3(cfg->handle.av.context, cfg->handle.av.codec); cfg->handle.av.context->bit_rate = 128000; cfg->handle.av.context->sample_fmt = AV_SAMPLE_FMT_FLTP; cfg->handle.av.context->sample_rate = samplerate; switch (*pchannels) { case 1: cfg->handle.av.context->channel_layout = AV_CH_LAYOUT_MONO; cfg->handle.av.context->channels = 1; break; default: cfg->handle.av.context->channel_layout = AV_CH_LAYOUT_STEREO; cfg->handle.av.context->channels = 2; break; } cfg->handle.av.context->profile = FF_PROFILE_AAC_LOW; if (1) { AVDictionary *opts = NULL; av_dict_set(&opts, "strict", "-2", 0); av_dict_set_int(&opts, "latm", 1, 0); if (avcodec_open2(cfg->handle.av.context, cfg->handle.av.codec, &opts) < 0) { av_dict_free(&opts); DPRINTF("Could not open codec\n"); goto av_error_1; } av_dict_free(&opts); } cfg->handle.av.frame = av_frame_alloc(); if (cfg->handle.av.frame == NULL) { DPRINTF("Could not allocate audio frame\n"); goto av_error_2; } cfg->handle.av.frame->nb_samples = cfg->handle.av.context->frame_size; cfg->handle.av.frame->format = cfg->handle.av.context->sample_fmt; cfg->handle.av.frame->channel_layout = cfg->handle.av.context->channel_layout; cfg->rem_in_size = av_samples_get_buffer_size(NULL, cfg->handle.av.context->channels, cfg->handle.av.context->frame_size, cfg->handle.av.context->sample_fmt, 0); cfg->rem_in_data = av_malloc(cfg->rem_in_size); if (cfg->rem_in_data == NULL) { DPRINTF("Could not allocate %u bytes sample buffer\n", (unsigned)cfg->rem_in_size); goto av_error_3; } retval = avcodec_fill_audio_frame(cfg->handle.av.frame, cfg->handle.av.context->channels, cfg->handle.av.context->sample_fmt, cfg->rem_in_data, cfg->rem_in_size, 0); if (retval < 0) { DPRINTF("Could not setup audio frame\n"); goto av_error_4; } break; av_error_4: av_free(cfg->rem_in_data); av_error_3: av_frame_free(&cfg->handle.av.frame); av_error_2: avcodec_close(cfg->handle.av.context); av_error_1: avformat_free_context(cfg->handle.av.format); cfg->handle.av.context = NULL; av_error_0: bt_close(pbe); return (-1); #endif default: bt_close(pbe); return (-1); } return (0); }
AVStream* AVFormatWriter::AddVideoStream(void) { AVCodecContext *c; AVStream *st; AVCodec *codec; st = avformat_new_stream(m_ctx, NULL); if (!st) { LOG(VB_RECORD, LOG_ERR, LOC + "AddVideoStream(): avformat_new_stream() failed"); return NULL; } st->id = 0; c = st->codec; codec = avcodec_find_encoder(m_ctx->oformat->video_codec); if (!codec) { LOG(VB_RECORD, LOG_ERR, LOC + "AddVideoStream(): avcodec_find_encoder() failed"); return NULL; } avcodec_get_context_defaults3(c, codec); c->codec = codec; c->codec_id = m_ctx->oformat->video_codec; c->codec_type = AVMEDIA_TYPE_VIDEO; c->bit_rate = m_videoBitrate; c->width = m_width; c->height = m_height; // c->sample_aspect_ratio.num = (int)floor(m_aspect * 10000); // c->sample_aspect_ratio.den = 10000; c->time_base = GetCodecTimeBase(); st->time_base.den = 90000; st->time_base.num = 1; st->r_frame_rate.num = 0; st->r_frame_rate.den = 0; c->gop_size = m_keyFrameDist; c->pix_fmt = AV_PIX_FMT_YUV420P; c->thread_count = m_encodingThreadCount; c->thread_type = FF_THREAD_SLICE; if (c->codec_id == AV_CODEC_ID_MPEG2VIDEO) { c->max_b_frames = 2; } else if (c->codec_id == AV_CODEC_ID_MPEG1VIDEO) { c->mb_decision = 2; } else if (c->codec_id == AV_CODEC_ID_H264) { // Try to provide the widest software/device support by automatically using // the Baseline profile where the given bitrate and resolution permits if ((c->height > 720) || // Approximate highest resolution supported by Baseline 3.1 (c->bit_rate > 1000000)) // 14,000 Kbps aka 14Mbps maximum permissable rate for Baseline 3.1 { c->level = 40; av_opt_set(c->priv_data, "profile", "main", 0); } else if ((c->height > 576) || // Approximate highest resolution supported by Baseline 3.0 (c->bit_rate > 1000000)) // 10,000 Kbps aka 10Mbps maximum permissable rate for Baseline 3.0 { c->level = 31; av_opt_set(c->priv_data, "profile", "baseline", 0); } else { c->level = 30; // Baseline 3.0 is the most widely supported, but it's limited to SD av_opt_set(c->priv_data, "profile", "baseline", 0); } c->coder_type = 0; c->max_b_frames = 0; c->slices = 8; c->flags |= CODEC_FLAG_LOOP_FILTER; c->me_cmp |= 1; c->me_method = ME_HEX; c->me_subpel_quality = 6; c->me_range = 16; c->keyint_min = 25; c->scenechange_threshold = 40; c->i_quant_factor = 0.71; c->b_frame_strategy = 1; c->qcompress = 0.6; c->qmin = 10; c->qmax = 51; c->max_qdiff = 4; c->refs = 3; c->trellis = 0; av_opt_set(c, "partitions", "i8x8,i4x4,p8x8,b8x8", 0); av_opt_set_int(c, "direct-pred", 1, 0); av_opt_set_int(c, "rc-lookahead", 0, 0); av_opt_set_int(c, "fast-pskip", 1, 0); av_opt_set_int(c, "mixed-refs", 1, 0); av_opt_set_int(c, "8x8dct", 0, 0); av_opt_set_int(c, "weightb", 0, 0); av_opt_set(c->priv_data, "preset", m_encodingPreset.toLatin1().constData(), 0); av_opt_set(c->priv_data, "tune", m_encodingTune.toLatin1().constData(), 0); } if(m_ctx->oformat->flags & AVFMT_GLOBALHEADER) c->flags |= CODEC_FLAG_GLOBAL_HEADER; return st; }
/* add a video output stream */ AVStream* CEncoder::add_video_stream(enum AVCodecID codec_id, char *name) { AVCodec *codec; AVStream *st; AVCodecContext *video_enc; /* find the video encoder */ if (name) { codec = avcodec_find_encoder_by_name(name); if (!codec) { av_log(NULL, AV_LOG_ERROR, "codec not found video encoder:%s\n", name); return NULL; } } else { codec = avcodec_find_encoder(codec_id); if (!codec) { av_log(NULL, AV_LOG_ERROR, "codec not found video by ID=%d\n", codec_id); return NULL; } } if(codec->type != AVMEDIA_TYPE_VIDEO) { av_log(NULL, AV_LOG_ERROR, "Invalid video encoder type '%s'\n", name); return NULL; } if (frame_pix_fmt == AV_PIX_FMT_NONE) { frame_pix_fmt = find_pixel_format(codec->pix_fmts); if (frame_pix_fmt == AV_PIX_FMT_NONE) frame_pix_fmt = codec->pix_fmts[0]; } st = avformat_new_stream(oc, NULL); if (!st) { av_log(NULL, AV_LOG_ERROR, "Could not alloc stream\n"); return NULL; } st->id = 0; video_enc = st->codec; video_enc->codec_type = AVMEDIA_TYPE_VIDEO; if (codec_id) video_enc->codec_id = codec_id; else video_enc->codec_id = codec->id; avcodec_get_context_defaults3(video_enc, codec); if (video_rc_max_rate != NO_VALUE) if (video_bit_rate > video_rc_max_rate) video_bit_rate = video_rc_max_rate; if ((sample_aspect_ratio.num != 1) && (sample_aspect_ratio.den != 1)) { sample_aspect_ratio = av_d2q((double)sample_aspect_ratio.num / (double)sample_aspect_ratio.den * (double)video_height/(double)video_width, 255); } if ((video_bit_rate == 0) && (video_qscale == 0)) video_qscale = 4; st->sample_aspect_ratio = sample_aspect_ratio; if (video_bit_rate) video_enc->bit_rate = video_bit_rate; video_enc->width = video_width; video_enc->height = video_height; video_enc->time_base.num = g_enc_opt.m_FrameNum; video_enc->time_base.den = g_enc_opt.m_FrameDen; if (video_gop_size) video_enc->gop_size = video_gop_size; /* emit one intra frame every twelve frames at most */ video_enc->pix_fmt = frame_pix_fmt; video_enc->sample_aspect_ratio = sample_aspect_ratio; if (video_codec_tag) video_enc->codec_tag = video_codec_tag; if (video_qscale) { video_enc->flags |= CODEC_FLAG_QSCALE; video_enc->global_quality = FF_QP2LAMBDA * video_qscale; } if (video_rc_max_rate != NO_VALUE) video_enc->rc_max_rate = video_rc_max_rate; if (video_rc_min_rate != NO_VALUE) video_enc->rc_min_rate = video_rc_min_rate; if (video_rc_buffer_size != NO_VALUE) video_enc->rc_buffer_size = video_rc_buffer_size; if (video_coder_type != NO_VALUE) video_enc->coder_type = video_coder_type; if (video_max_b_frames != NO_VALUE) video_enc->max_b_frames = video_max_b_frames; if (video_level != NO_VALUE) video_enc->level = video_level; if (video_sc_threshold != NO_VALUE) video_enc->scenechange_threshold = video_sc_threshold; if (video_qmin != NO_VALUE) video_enc->qmin = video_qmin; if (video_qmax != NO_VALUE) video_enc->qmax = video_qmax; if (video_qdiff != NO_VALUE) video_enc->max_qdiff = video_qdiff; if (video_i_qfactor != NO_VALUE) video_enc->b_quant_factor = video_i_qfactor; if (video_rc_eq) video_enc->rc_eq = av_strdup(video_rc_eq); if (video_qcomp != NO_VALUE) video_enc->qcompress = video_qcomp; if (video_me_range != NO_VALUE) video_enc->me_range = video_me_range; if (thread_count) video_enc->thread_count = thread_count; switch(video_enc->codec_id) { case CODEC_ID_MPEG2VIDEO: video_enc->max_b_frames = 2; break; case CODEC_ID_MPEG1VIDEO: video_enc->mb_decision = 2; break; default: break; } // some formats want stream headers to be separate if(oc->oformat->flags & AVFMT_GLOBALHEADER) video_enc->flags |= CODEC_FLAG_GLOBAL_HEADER; /* open the codec */ if (avcodec_open2(video_enc, codec, &video_options) < 0) { av_log(NULL, AV_LOG_ERROR, "could not open video codec\n"); return NULL; } if (oc->oformat->flags & AVFMT_RAWPICTURE) { av_log(NULL, AV_LOG_ERROR, "Raw Picture ?\n"); return NULL; } video_outbuf_size = video_width * video_height * 16; if (video_outbuf_size < FF_MIN_BUFFER_SIZE) video_outbuf_size = FF_MIN_BUFFER_SIZE; video_outbuf = (uint8_t *)av_malloc(video_outbuf_size); return st; }
int FFMPEG_Wrapper::init(int input_width, int input_height, const ServerConfiguration& config) { boost::mutex::scoped_lock lock(frame_mutex_); time_started_ = boost::posix_time::microsec_clock::local_time(); config_ = config; input_width_ = input_width; input_height_ = input_height; output_width_ = config.frame_width_; output_height_ = config.frame_height_; if (output_width_<0) output_width_ = input_width_; if (output_height_<0) output_height_ = input_height_; av_lockmgr_register(&ff_lockmgr); /* register all the codecs */ avcodec_register_all(); av_register_all(); // lookup webm codec avformat_alloc_output_context2(&ffmpeg_format_context_, NULL, config_.codec_.c_str(), NULL); if (!ffmpeg_format_context_) { return -1; } ffmpeg_output_format_ = ffmpeg_format_context_->oformat; /* Add the audio and video streams using the default format codecs * and initialize the codecs. */ ffmpeg_video_st_ = NULL; if (ffmpeg_output_format_->video_codec != AV_CODEC_ID_NONE) { /* find the video encoder */ ffmpeg_codec_ = avcodec_find_encoder(ffmpeg_output_format_->video_codec); if (!(ffmpeg_codec_)) { fprintf(stderr, "Codec not found (%s)\n",config_.codec_.c_str()); return -1; } ffmpeg_video_st_ = avformat_new_stream(ffmpeg_format_context_, ffmpeg_codec_); if (!ffmpeg_video_st_) { fprintf(stderr, "Could not alloc stream\n"); return -1; } ffmpeg_codec_context_ = ffmpeg_video_st_->codec; avcodec_get_context_defaults3(ffmpeg_codec_context_, ffmpeg_codec_); ////////////////////////////////////////////// // ffmpeg codec configuration ////////////////////////////////////////////// ffmpeg_codec_context_->codec_id = ffmpeg_output_format_->video_codec; ffmpeg_codec_context_->bit_rate = config_.bitrate_; ffmpeg_codec_context_->width = output_width_; ffmpeg_codec_context_->height = output_height_; ffmpeg_codec_context_->delay = 0; ffmpeg_codec_context_->time_base.den = config_.framerate_+3; //increased framerate to compensate playback delay ffmpeg_codec_context_->time_base.num = 1; ffmpeg_codec_context_->gop_size = config_.gop_; /* emit one intra ffmpeg_frame_ every twelve frames at most */ ffmpeg_codec_context_->pix_fmt = PIX_FMT_YUV420P; ffmpeg_codec_context_->max_b_frames = 0; av_opt_set(ffmpeg_codec_context_->priv_data, "quality", config_.profile_.c_str(), 0); av_opt_set(ffmpeg_codec_context_->priv_data, "deadline", "1", 0); av_opt_set(ffmpeg_codec_context_->priv_data, "auto-alt-ref", "0", 0); // lag in frames av_opt_set(ffmpeg_codec_context_->priv_data, "lag-in-frames", "1", 0); av_opt_set(ffmpeg_codec_context_->priv_data, "rc_lookahead", "1", 0); av_opt_set(ffmpeg_codec_context_->priv_data, "drop_frame", "1", 0); // enable error-resilient coding av_opt_set(ffmpeg_codec_context_->priv_data, "error-resilient", "1", 0); // buffer size of rate controller (length: rc_buffer_size/bitrate * 1000) ms int bufsize = 10;//ffmpeg_codec_context_->bit_rate/10; ffmpeg_codec_context_->rc_buffer_size = bufsize; // prebuffering at decoder ffmpeg_codec_context_->rc_initial_buffer_occupancy = bufsize ;//bitrate/3; av_opt_set_int(ffmpeg_codec_context_->priv_data, "bufsize", bufsize, 0); av_opt_set_int(ffmpeg_codec_context_->priv_data, "buf-initial", bufsize, 0); av_opt_set_int(ffmpeg_codec_context_->priv_data, "buf-optimal", bufsize, 0); // buffer agressivity ffmpeg_codec_context_->rc_buffer_aggressivity = 0.5; // Quality settings //ffmpeg_codec_context_->qmin = 50; //ffmpeg_codec_context_->qmax = 62; if (config_.quality_>0) ffmpeg_codec_context_->qmin = config_.quality_; //ffmpeg_codec_context_->frame_skip_threshold = 100; /* Some formats want stream headers to be separate. */ if (ffmpeg_format_context_->oformat->flags & AVFMT_GLOBALHEADER) ffmpeg_codec_context_->flags |= CODEC_FLAG_GLOBAL_HEADER; } if (ffmpeg_video_st_) { int ret; /* open the codec */ { boost::mutex::scoped_lock lock(codec_mutex_); if (avcodec_open2(ffmpeg_codec_context_, ffmpeg_codec_, NULL) < 0) { fprintf(stderr, "Could not open video codec\n"); return -1; } } /* allocate and init a re-usable ffmpeg_frame_ */ ffmpeg_frame_ = avcodec_alloc_frame(); if (!ffmpeg_frame_) { fprintf(stderr, "Could not allocate video ffmpeg_frame_\n"); return -1; } /* Allocate the encoded raw picture. */ ret = avpicture_alloc(ffmpeg_dst_picture_, ffmpeg_codec_context_->pix_fmt, output_width_, output_height_); if (ret < 0) { fprintf(stderr, "Could not allocate picture\n"); return -1; } /* If the output format is not YUV420P, then a temporary YUV420P * picture is needed too. It is then converted to the required * output format. */ ret = avpicture_alloc(ffmpeg_src_picture_, AV_PIX_FMT_RGB24, input_width_, input_height_); if (ret < 0) { fprintf(stderr, "Could not allocate temporary picture\n"); return -1; } /* copy data and linesize picture pointers to ffmpeg_frame_ */ *((AVPicture *)ffmpeg_frame_) = *ffmpeg_dst_picture_; av_dump_format(ffmpeg_format_context_, 0, "", 1); ffmpeg_output_format_->flags |= AVFMT_NOFILE; if (ffmpeg_frame_) ffmpeg_frame_->pts = 0; } init_ = true; return 0; }
MediaRecorder::MediaRecorder(const char * outfile,int width, int height) { audiofailed = false; /* INIT SOUND RECORDING */ debug_samples_out = fopen("audiosamples.s16","wb"); audio_samples_written = 0; pa_context* pactx; pa_mainloop * m = pa_mainloop_new(); m_api = pa_mainloop_get_api(m); pactx = pa_context_new(m_api,"Rec1"); if ( pa_context_connect(pactx,NULL,(pa_context_flags_t)0,NULL) < 0 ) printf("Cannot connect to pulseaudio\n"); int ret; pa_context_set_state_callback(pactx, context_state_callback, this); pa_mainloop_run(m,&ret); std::cout << "Use source: " << monitorsources[defaultsink] << std::endl; static const pa_sample_spec ss = { .format = PA_SAMPLE_S16LE, .rate = 44100, .channels = 2 }; pa_context_disconnect(pactx); int error; s = pa_simple_new(NULL,"GLCAP Record",PA_STREAM_RECORD,monitorsources[defaultsink].c_str(), "record", &ss, NULL,NULL , &error); if ( !s ) { printf("Cannot create pa_simple\n"); } run = true; ready = false; firstframe = true; this->width = width; this->height = height; pthread_mutex_init(&encode_mutex,NULL); pthread_mutex_init(&sound_buffer_lock,NULL); pthread_cond_init(&encode_cond,NULL); pthread_create(&encode_thread,NULL,(void*(*)(void*))&MediaRecorder::EncodingThread,this); av_log_set_level(AV_LOG_DEBUG); outCtx = avformat_alloc_context(); outCtx->oformat = av_guess_format(NULL, outfile, NULL); snprintf(outCtx->filename, sizeof(outCtx->filename), "%s", outfile); codec = avcodec_find_encoder(AV_CODEC_ID_MPEG4); acodec = avcodec_find_encoder(AV_CODEC_ID_MP2); ctx = avcodec_alloc_context3(codec); actx = avcodec_alloc_context3(acodec); avcodec_get_context_defaults3(actx,acodec); avcodec_get_context_defaults3(ctx,codec); ctx->width = width; ctx->height = height; ctx->bit_rate = 6000*1000; std::cout << ctx->time_base.den << " " << ctx->time_base.num << std::endl; ctx->time_base.den = TIMEBASE; ctx->time_base.num = 1; ctx->thread_count = 4; ctx->qmin = 2; ctx->qmax = 31; ctx->b_sensitivity = 100; ctx->gop_size = 1; ctx->me_method = 1; ctx->global_quality = 100; ctx->lowres = 0; ctx->bit_rate_tolerance = 200000; actx->sample_fmt = AV_SAMPLE_FMT_S16; actx->sample_rate = 44100; actx->channels = 2; actx->time_base.den = 44100; actx->time_base.num = 1; actx->bit_rate = 128000; actx->frame_size = 8192; actx->channel_layout = 3; /* ctx->compression_level = 0; ctx->trellis = 0; ctx->gop_size = 1; /* emit one intra frame every ten frames */ /*ctx->me_pre_cmp = 0; ctx->me_cmp = 0; ctx->me_sub_cmp = 0; ctx->mb_cmp = 2; ctx->pre_dia_size = 0; ctx->dia_size = 1; ctx->quantizer_noise_shaping = 0; // qns=0 ctx->noise_reduction = 0; // nr=0 ctx->mb_decision = 0; // mbd=0 ("realtime" encoding) ctx->flags &= ~CODEC_FLAG_QPEL; ctx->flags &= ~CODEC_FLAG_4MV; ctx->trellis = 0; ctx->flags &= ~CODEC_FLAG_CBP_RD; ctx->flags &= ~CODEC_FLAG_QP_RD; ctx->flags &= ~CODEC_FLAG_MV0;*/ //ctx->s ctx->pix_fmt = PIX_FMT_YUV420P; if (avcodec_open2(ctx, codec, NULL) < 0) { fprintf(stderr, "Could not open codec\n"); } if (avcodec_open2(actx, acodec, NULL) < 0) { fprintf(stderr, "Could not open audio codec\n"); audiofailed = true; } printf("frame_size: %d\n",actx->frame_size); pthread_create(&record_sound_thread,NULL,(void*(*)(void*))&MediaRecorder::RecordingThread,this); AVStream* s = av_new_stream(outCtx,0); s->codec = ctx; s->r_frame_rate.den = TIMEBASE; s->r_frame_rate.num = 1; if (!audiofailed ) { AVStream* as = av_new_stream(outCtx,1); as->codec = actx; as->r_frame_rate.den = 44100; as->r_frame_rate.num = 1; } picture = alloc_picture(PIX_FMT_YUV420P, ctx->width, ctx->height); if (!picture) { fprintf(stderr, "Could not allocate picture\n"); exit(1); } tmp_picture = NULL; tmp_picture = alloc_picture(PIX_FMT_RGBA, ctx->width, ctx->height); if (!tmp_picture) { fprintf(stderr, "Could not allocate temporary picture\n"); exit(1); } img_convert_ctx = sws_getContext(ctx->width, ctx->height, PIX_FMT_RGBA, ctx->width, ctx->height, PIX_FMT_YUV420P, SWS_FAST_BILINEAR , NULL, NULL, NULL); if (img_convert_ctx == NULL) { fprintf(stderr, "Cannot initialize the conversion context\n"); exit(1); } av_dump_format(outCtx, 0, outfile, 1); avio_open2(&outCtx->pb, outfile, AVIO_FLAG_WRITE,NULL,NULL); avformat_write_header(outCtx,NULL); } MediaRecorder::~MediaRecorder() { run = false; ready = false; pthread_cond_broadcast(&encode_cond); printf("Joining thread..\n"); pthread_join(encode_thread,NULL); printf("Joining recording thread..\n"); pthread_join(record_sound_thread,NULL); printf("Done\n"); av_write_trailer(outCtx); av_free(picture); avformat_free_context(outCtx); pa_simple_free(s); fclose(debug_samples_out); } int fcount = 0; void MediaRecorder::AppendFrame(float time, int width, int height, char* data) { if ( !ready ) return ; printf("AppendFrame\n"); this->time = getcurrenttime2(); if ( firstframe ) { starttime = getcurrenttime2(); firstframe = false; } this->height = height; this->width = width; m_data = data; ready = false; pthread_cond_broadcast(&encode_cond); /*int i = 0; unsigned int numpixels = width * height; unsigned int ui = numpixels; unsigned int vi = numpixels + numpixels / 4; for ( int j = 0; j < height; j++ ) { for ( int k = 0; k < width; k++ ) { int sR = data[i*4+0]; int sG = data[i*4+1]; int sB = data[i*4+2]; picture->data[0][i] = ( (66*sR + 129*sG + 25*sB + 128) >> 8) + 16; if (0 == j%2 && 0 == k%2) { picture->data[0][ui++] = ( (-38*sR - 74*sG + 112*sB + 128) >> 8) + 128; picture->data[0][vi++] = ( (112*sR - 94*sG - 18*sB + 128) >> 8) + 128; } i++; } }*/ // printf("End flip %f\n",(float)getcurrenttime2()); //memcpy(tmp_picture->data[0],data,width*height*4); } void MediaRecorder::EncodingThread() { while ( run ) { printf("Encode thread ready\n"); ready = true; pthread_cond_wait(&encode_cond,&encode_mutex); if (!run) { printf("Encoding finished\n"); break; } for ( int y = 0; y < height; y++ ) { /*for ( int x = 0; x < width; x++ ) {*/ char r,g,b; int oldindex = (y*width); int newindex = ((height-1-y)*width); memcpy(&tmp_picture->data[0][(newindex)*4],&m_data[oldindex*4],width*4); /* r = data[oldindex*4+0]; g = data[oldindex*4+1]; b = data[oldindex*4+2]; tmp_picture->data[0][(newindex)*4+0] = r; tmp_picture->data[0][(newindex)*4+1] = g; tmp_picture->data[0][(newindex)*4+2] = b; */ // } } sws_scale(img_convert_ctx,tmp_picture->data,tmp_picture->linesize,0,height,picture->data,picture->linesize); AVPacket p; av_init_packet(&p); p.data = NULL; p.size = 0; picture->pts = int64_t((time-starttime)*TIMEBASE); uint64_t vpts = picture->pts; // picture->pts = time*30.0; int got_frame; printf("%p %p\n",ctx, picture); if(avcodec_encode_video2(ctx, &p, picture, &got_frame) < 0) return; if(got_frame) { // outContainer is "mp4" p.pts = vpts; p.dts = AV_NOPTS_VALUE; av_write_frame(outCtx, &p); av_free_packet(&p); } //sleep(1); printf("End enc frame %f, pts %lld\n",(float)getcurrenttime2(),picture->pts); AVFrame * aframe = avcodec_alloc_frame(); bool unlocked = false; while ( sound_buffers.size() > 0 ) { uint64_t apts = audio_samples_written; /* if ( apts > vpts ) break;*/ pthread_mutex_lock(&sound_buffer_lock); short * buf = sound_buffers.front(); sound_buffers.pop_front(); pthread_mutex_unlock(&sound_buffer_lock); if (!audiofailed ) { unlocked = true; aframe->nb_samples = actx->frame_size; aframe->channel_layout = actx->channel_layout; aframe->format = AV_SAMPLE_FMT_S16; aframe->channels = actx->channels; avcodec_fill_audio_frame(aframe,actx->channels,AV_SAMPLE_FMT_S16,(char*)buf,actx->frame_size*2*2,0); // avcodec_fill_audio_frame(aframe,actx->channels,actx->sample_fmt,(char*)buf,actx->frame_size*2,0); printf("sound_buffers.size() = %d\n",sound_buffers.size()); av_init_packet(&p); p.data = NULL; p.size = 0; avcodec_encode_audio2(actx,&p,aframe,&got_frame); if ( got_frame ) { p.stream_index = 1; p.flags |= AV_PKT_FLAG_KEY; av_write_frame(outCtx,&p); av_free_packet(&p); } audio_samples_written += actx->frame_size;//samples/2 each channel } //printf("Consumed 1024 samples\n"); delete[] buf; } /* if ( !unlocked ) pthread_mutex_unlock(&sound_buffer_lock);*/ avcodec_free_frame(&aframe); } } bool MediaRecorder::isReady() { return ready; }
// add a video output stream static int AddVideoStream() { g_pVStream = avformat_new_stream(g_pContainer, g_pVCodec); if (!g_pVStream) return FatalError("Could not allocate video stream"); g_pVideo = g_pVStream->codec; avcodec_get_context_defaults3(g_pVideo, g_pVCodec); g_pVideo->codec_id = g_pVCodec->id; // put parameters // resolution must be a multiple of two g_pVideo->width = g_Width & ~1; // make even (dimensions should be even) g_pVideo->height = g_Height & ~1; // make even /* time base: this is the fundamental unit of time (in seconds) in terms of which frame timestamps are represented. for fixed-fps content, timebase should be 1/framerate and timestamp increments should be identically 1. */ g_pVideo->time_base.den = g_pVStream->time_base.den = g_Framerate.num; g_pVideo->time_base.num = g_pVStream->time_base.num = g_Framerate.den; g_pVideo->pix_fmt = AV_PIX_FMT_YUV420P; // set quality if (g_VQuality > 100) g_pVideo->bit_rate = g_VQuality; else { g_pVideo->flags |= AV_CODEC_FLAG_QSCALE; g_pVideo->global_quality = g_VQuality*FF_QP2LAMBDA; } // some formats want stream headers to be separate if (g_pFormat->flags & AVFMT_GLOBALHEADER) g_pVideo->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; #if LIBAVCODEC_VERSION_MAJOR < 53 // for some versions of ffmpeg x264 options must be set explicitly if (strcmp(g_pVCodec->name, "libx264") == 0) { g_pVideo->coder_type = FF_CODER_TYPE_AC; g_pVideo->flags |= CODEC_FLAG_LOOP_FILTER; g_pVideo->crf = 23; g_pVideo->thread_count = 3; g_pVideo->me_cmp = FF_CMP_CHROMA; g_pVideo->partitions = X264_PART_I8X8 | X264_PART_I4X4 | X264_PART_P8X8 | X264_PART_B8X8; g_pVideo->me_method = ME_HEX; g_pVideo->me_subpel_quality = 7; g_pVideo->me_range = 16; g_pVideo->gop_size = 250; g_pVideo->keyint_min = 25; g_pVideo->scenechange_threshold = 40; g_pVideo->i_quant_factor = 0.71; g_pVideo->b_frame_strategy = 1; g_pVideo->qcompress = 0.6; g_pVideo->qmin = 10; g_pVideo->qmax = 51; g_pVideo->max_qdiff = 4; g_pVideo->max_b_frames = 3; g_pVideo->refs = 3; g_pVideo->directpred = 1; g_pVideo->trellis = 1; g_pVideo->flags2 = CODEC_FLAG2_BPYRAMID | CODEC_FLAG2_MIXED_REFS | CODEC_FLAG2_WPRED | CODEC_FLAG2_8X8DCT | CODEC_FLAG2_FASTPSKIP; g_pVideo->weighted_p_pred = 2; } #endif // open the codec if (avcodec_open2(g_pVideo, g_pVCodec, NULL) < 0) return FatalError("Could not open video codec %s", g_pVCodec->long_name); g_pVFrame = av_frame_alloc(); if (!g_pVFrame) return FatalError("Could not allocate frame"); g_pVFrame->width = g_Width; g_pVFrame->height = g_Height; g_pVFrame->format = AV_PIX_FMT_YUV420P; g_pVFrame->linesize[0] = g_Width; g_pVFrame->linesize[1] = g_Width/2; g_pVFrame->linesize[2] = g_Width/2; g_pVFrame->linesize[3] = 0; return 0; }
void avcodec_get_context_defaults2(AVCodecContext *s, enum AVMediaType codec_type){ AVCodec c= {0}; c.type= codec_type; avcodec_get_context_defaults3(s, &c); }
/********************************************************************** * avformatInit ********************************************************************** * Allocates hb_mux_data_t structures, create file and write headers *********************************************************************/ static int avformatInit( hb_mux_object_t * m ) { hb_job_t * job = m->job; hb_audio_t * audio; hb_mux_data_t * track; int meta_mux; int max_tracks; int ii, ret; const char *muxer_name = NULL; uint8_t default_track_flag = 1; uint8_t need_fonts = 0; char *lang; m->delay = -1; max_tracks = 1 + hb_list_count( job->list_audio ) + hb_list_count( job->list_subtitle ); m->tracks = calloc(max_tracks, sizeof(hb_mux_data_t*)); m->oc = avformat_alloc_context(); if (m->oc == NULL) { hb_error( "Could not initialize avformat context." ); goto error; } switch (job->mux) { case HB_MUX_AV_MP4: m->time_base.num = 1; m->time_base.den = 90000; if( job->ipod_atom ) muxer_name = "ipod"; else muxer_name = "mp4"; meta_mux = META_MUX_MP4; break; case HB_MUX_AV_MKV: // libavformat is essentially hard coded such that it only // works with a timebase of 1/1000 m->time_base.num = 1; m->time_base.den = 1000; muxer_name = "matroska"; meta_mux = META_MUX_MKV; break; default: { hb_error("Invalid Mux %x", job->mux); goto error; } } m->oc->oformat = av_guess_format(muxer_name, NULL, NULL); if(m->oc->oformat == NULL) { hb_error("Could not guess output format %s", muxer_name); goto error; } av_strlcpy(m->oc->filename, job->file, sizeof(m->oc->filename)); ret = avio_open2(&m->oc->pb, job->file, AVIO_FLAG_WRITE, &m->oc->interrupt_callback, NULL); if( ret < 0 ) { hb_error( "avio_open2 failed, errno %d", ret); goto error; } /* Video track */ track = m->tracks[m->ntracks++] = calloc(1, sizeof( hb_mux_data_t ) ); job->mux_data = track; track->type = MUX_TYPE_VIDEO; track->st = avformat_new_stream(m->oc, NULL); if (track->st == NULL) { hb_error("Could not initialize video stream"); goto error; } track->st->time_base = m->time_base; avcodec_get_context_defaults3(track->st->codec, NULL); track->st->codec->codec_type = AVMEDIA_TYPE_VIDEO; track->st->codec->flags |= CODEC_FLAG_GLOBAL_HEADER; uint8_t *priv_data = NULL; int priv_size = 0; switch (job->vcodec) { case HB_VCODEC_X264: case HB_VCODEC_QSV_H264: track->st->codec->codec_id = AV_CODEC_ID_H264; /* Taken from x264 muxers.c */ priv_size = 5 + 1 + 2 + job->config.h264.sps_length + 1 + 2 + job->config.h264.pps_length; priv_data = av_malloc(priv_size); if (priv_data == NULL) { hb_error("malloc failure"); goto error; } priv_data[0] = 1; priv_data[1] = job->config.h264.sps[1]; /* AVCProfileIndication */ priv_data[2] = job->config.h264.sps[2]; /* profile_compat */ priv_data[3] = job->config.h264.sps[3]; /* AVCLevelIndication */ priv_data[4] = 0xff; // nalu size length is four bytes priv_data[5] = 0xe1; // one sps priv_data[6] = job->config.h264.sps_length >> 8; priv_data[7] = job->config.h264.sps_length; memcpy(priv_data+8, job->config.h264.sps, job->config.h264.sps_length); priv_data[8+job->config.h264.sps_length] = 1; // one pps priv_data[9+job->config.h264.sps_length] = job->config.h264.pps_length >> 8; priv_data[10+job->config.h264.sps_length] = job->config.h264.pps_length; memcpy(priv_data+11+job->config.h264.sps_length, job->config.h264.pps, job->config.h264.pps_length ); break; case HB_VCODEC_FFMPEG_MPEG4: track->st->codec->codec_id = AV_CODEC_ID_MPEG4; if (job->config.mpeg4.length != 0) { priv_size = job->config.mpeg4.length; priv_data = av_malloc(priv_size); if (priv_data == NULL) { hb_error("malloc failure"); goto error; } memcpy(priv_data, job->config.mpeg4.bytes, priv_size); } break; case HB_VCODEC_FFMPEG_MPEG2: track->st->codec->codec_id = AV_CODEC_ID_MPEG2VIDEO; if (job->config.mpeg4.length != 0) { priv_size = job->config.mpeg4.length; priv_data = av_malloc(priv_size); if (priv_data == NULL) { hb_error("malloc failure"); goto error; } memcpy(priv_data, job->config.mpeg4.bytes, priv_size); } break; case HB_VCODEC_THEORA: { track->st->codec->codec_id = AV_CODEC_ID_THEORA; int size = 0; ogg_packet *ogg_headers[3]; for (ii = 0; ii < 3; ii++) { ogg_headers[ii] = (ogg_packet *)job->config.theora.headers[ii]; size += ogg_headers[ii]->bytes + 2; } priv_size = size; priv_data = av_malloc(priv_size); if (priv_data == NULL) { hb_error("malloc failure"); goto error; } size = 0; for(ii = 0; ii < 3; ii++) { AV_WB16(priv_data + size, ogg_headers[ii]->bytes); size += 2; memcpy(priv_data+size, ogg_headers[ii]->packet, ogg_headers[ii]->bytes); size += ogg_headers[ii]->bytes; } } break; default: hb_error("muxavformat: Unknown video codec: %x", job->vcodec); goto error; } track->st->codec->extradata = priv_data; track->st->codec->extradata_size = priv_size; if (job->anamorphic.mode > 0) { track->st->sample_aspect_ratio.num = job->anamorphic.par_width; track->st->sample_aspect_ratio.den = job->anamorphic.par_height; track->st->codec->sample_aspect_ratio.num = job->anamorphic.par_width; track->st->codec->sample_aspect_ratio.den = job->anamorphic.par_height; } else { track->st->sample_aspect_ratio.num = 1; track->st->sample_aspect_ratio.den = 1; track->st->codec->sample_aspect_ratio.num = 1; track->st->codec->sample_aspect_ratio.den = 1; } track->st->codec->width = job->width; track->st->codec->height = job->height; track->st->disposition |= AV_DISPOSITION_DEFAULT; int vrate_base, vrate; if( job->pass == 2 ) { hb_interjob_t * interjob = hb_interjob_get( job->h ); vrate_base = interjob->vrate_base; vrate = interjob->vrate; } else { vrate_base = job->vrate_base; vrate = job->vrate; } // If the vrate is 27000000, there's a good chance this is // a standard rate that we have in our hb_video_rates table. // Because of rounding errors and approximations made while // measuring framerate, the actual value may not be exact. So // we look for rates that are "close" and make an adjustment // to fps.den. if (vrate == 27000000) { const hb_rate_t *video_framerate = NULL; while ((video_framerate = hb_video_framerate_get_next(video_framerate)) != NULL) { if (abs(vrate_base - video_framerate->rate) < 10) { vrate_base = video_framerate->rate; break; } } } hb_reduce(&vrate_base, &vrate, vrate_base, vrate); if (job->mux == HB_MUX_AV_MP4) { // libavformat mp4 muxer requires that the codec time_base have the // same denominator as the stream time_base, it uses it for the // mdhd timescale. double scale = (double)track->st->time_base.den / vrate; track->st->codec->time_base.den = track->st->time_base.den; track->st->codec->time_base.num = vrate_base * scale; } else { track->st->codec->time_base.num = vrate_base; track->st->codec->time_base.den = vrate; } /* add the audio tracks */ for(ii = 0; ii < hb_list_count( job->list_audio ); ii++ ) { audio = hb_list_item( job->list_audio, ii ); track = m->tracks[m->ntracks++] = calloc(1, sizeof( hb_mux_data_t ) ); audio->priv.mux_data = track; track->type = MUX_TYPE_AUDIO; track->st = avformat_new_stream(m->oc, NULL); if (track->st == NULL) { hb_error("Could not initialize audio stream"); goto error; } avcodec_get_context_defaults3(track->st->codec, NULL); track->st->codec->codec_type = AVMEDIA_TYPE_AUDIO; track->st->codec->flags |= CODEC_FLAG_GLOBAL_HEADER; if (job->mux == HB_MUX_AV_MP4) { track->st->codec->time_base.num = audio->config.out.samples_per_frame; track->st->codec->time_base.den = audio->config.out.samplerate; track->st->time_base.num = 1; track->st->time_base.den = audio->config.out.samplerate; } else { track->st->codec->time_base = m->time_base; } priv_data = NULL; priv_size = 0; switch (audio->config.out.codec & HB_ACODEC_MASK) { case HB_ACODEC_DCA: case HB_ACODEC_DCA_HD: track->st->codec->codec_id = AV_CODEC_ID_DTS; break; case HB_ACODEC_AC3: track->st->codec->codec_id = AV_CODEC_ID_AC3; break; case HB_ACODEC_LAME: case HB_ACODEC_MP3: track->st->codec->codec_id = AV_CODEC_ID_MP3; break; case HB_ACODEC_VORBIS: { track->st->codec->codec_id = AV_CODEC_ID_VORBIS; int jj, size = 0; ogg_packet *ogg_headers[3]; for (jj = 0; jj < 3; jj++) { ogg_headers[jj] = (ogg_packet *)audio->priv.config.vorbis.headers[jj]; size += ogg_headers[jj]->bytes + 2; } priv_size = size; priv_data = av_malloc(priv_size); if (priv_data == NULL) { hb_error("malloc failure"); goto error; } size = 0; for(jj = 0; jj < 3; jj++) { AV_WB16(priv_data + size, ogg_headers[jj]->bytes); size += 2; memcpy(priv_data+size, ogg_headers[jj]->packet, ogg_headers[jj]->bytes); size += ogg_headers[jj]->bytes; } } break; case HB_ACODEC_FFFLAC: case HB_ACODEC_FFFLAC24: track->st->codec->codec_id = AV_CODEC_ID_FLAC; if (audio->priv.config.extradata.bytes) { priv_size = audio->priv.config.extradata.length; priv_data = av_malloc(priv_size); if (priv_data == NULL) { hb_error("malloc failure"); goto error; } memcpy(priv_data, audio->priv.config.extradata.bytes, audio->priv.config.extradata.length); } break; case HB_ACODEC_FAAC: case HB_ACODEC_FFAAC: case HB_ACODEC_CA_AAC: case HB_ACODEC_CA_HAAC: case HB_ACODEC_FDK_AAC: case HB_ACODEC_FDK_HAAC: track->st->codec->codec_id = AV_CODEC_ID_AAC; if (audio->priv.config.extradata.bytes) { priv_size = audio->priv.config.extradata.length; priv_data = av_malloc(priv_size); if (priv_data == NULL) { hb_error("malloc failure"); goto error; } memcpy(priv_data, audio->priv.config.extradata.bytes, audio->priv.config.extradata.length); } break; default: hb_error("muxavformat: Unknown audio codec: %x", audio->config.out.codec); goto error; } track->st->codec->extradata = priv_data; track->st->codec->extradata_size = priv_size; if( default_track_flag ) { track->st->disposition |= AV_DISPOSITION_DEFAULT; default_track_flag = 0; } lang = lookup_lang_code(job->mux, audio->config.lang.iso639_2 ); if (lang != NULL) { av_dict_set(&track->st->metadata, "language", lang, 0); } track->st->codec->sample_rate = audio->config.out.samplerate; if (audio->config.out.codec & HB_ACODEC_PASS_FLAG) { track->st->codec->channels = av_get_channel_layout_nb_channels(audio->config.in.channel_layout); track->st->codec->channel_layout = audio->config.in.channel_layout; } else { track->st->codec->channels = hb_mixdown_get_discrete_channel_count(audio->config.out.mixdown); track->st->codec->channel_layout = hb_ff_mixdown_xlat(audio->config.out.mixdown, NULL); } char *name; if (audio->config.out.name == NULL) { switch (track->st->codec->channels) { case 1: name = "Mono"; break; case 2: name = "Stereo"; break; default: name = "Surround"; break; } } else { name = audio->config.out.name; } av_dict_set(&track->st->metadata, "title", name, 0); } char * subidx_fmt = "size: %dx%d\n" "org: %d, %d\n" "scale: 100%%, 100%%\n" "alpha: 100%%\n" "smooth: OFF\n" "fadein/out: 50, 50\n" "align: OFF at LEFT TOP\n" "time offset: 0\n" "forced subs: %s\n" "palette: %06x, %06x, %06x, %06x, %06x, %06x, " "%06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x\n" "custom colors: OFF, tridx: 0000, " "colors: 000000, 000000, 000000, 000000\n"; int subtitle_default = -1; for( ii = 0; ii < hb_list_count( job->list_subtitle ); ii++ ) { hb_subtitle_t *subtitle = hb_list_item( job->list_subtitle, ii ); if( subtitle->config.dest == PASSTHRUSUB ) { if ( subtitle->config.default_track ) subtitle_default = ii; } } // Quicktime requires that at least one subtitle is enabled, // else it doesn't show any of the subtitles. // So check to see if any of the subtitles are flagged to be // the defualt. The default will the the enabled track, else // enable the first track. if (job->mux == HB_MUX_AV_MP4 && subtitle_default == -1) { subtitle_default = 0; } for( ii = 0; ii < hb_list_count( job->list_subtitle ); ii++ ) { hb_subtitle_t * subtitle; uint32_t rgb[16]; char subidx[2048]; int len; subtitle = hb_list_item( job->list_subtitle, ii ); if (subtitle->config.dest != PASSTHRUSUB) continue; track = m->tracks[m->ntracks++] = calloc(1, sizeof( hb_mux_data_t ) ); subtitle->mux_data = track; track->type = MUX_TYPE_SUBTITLE; track->st = avformat_new_stream(m->oc, NULL); if (track->st == NULL) { hb_error("Could not initialize subtitle stream"); goto error; } avcodec_get_context_defaults3(track->st->codec, NULL); track->st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE; track->st->codec->flags |= CODEC_FLAG_GLOBAL_HEADER; track->st->time_base = m->time_base; track->st->codec->time_base = m->time_base; track->st->codec->width = subtitle->width; track->st->codec->height = subtitle->height; priv_data = NULL; priv_size = 0; switch (subtitle->source) { case VOBSUB: { int jj; track->st->codec->codec_id = AV_CODEC_ID_DVD_SUBTITLE; for (jj = 0; jj < 16; jj++) rgb[jj] = hb_yuv2rgb(subtitle->palette[jj]); len = snprintf(subidx, 2048, subidx_fmt, subtitle->width, subtitle->height, 0, 0, "OFF", rgb[0], rgb[1], rgb[2], rgb[3], rgb[4], rgb[5], rgb[6], rgb[7], rgb[8], rgb[9], rgb[10], rgb[11], rgb[12], rgb[13], rgb[14], rgb[15]); priv_size = len + 1; priv_data = av_malloc(priv_size); if (priv_data == NULL) { hb_error("malloc failure"); goto error; } memcpy(priv_data, subidx, priv_size); } break; case PGSSUB: { track->st->codec->codec_id = AV_CODEC_ID_HDMV_PGS_SUBTITLE; } break; case SSASUB: { if (job->mux == HB_MUX_AV_MP4) { track->st->codec->codec_id = AV_CODEC_ID_MOV_TEXT; } else { track->st->codec->codec_id = AV_CODEC_ID_SSA; need_fonts = 1; if (subtitle->extradata_size) { priv_size = subtitle->extradata_size; priv_data = av_malloc(priv_size); if (priv_data == NULL) { hb_error("malloc failure"); goto error; } memcpy(priv_data, subtitle->extradata, priv_size); } } } break; case CC608SUB: case CC708SUB: case UTF8SUB: case TX3GSUB: case SRTSUB: { if (job->mux == HB_MUX_AV_MP4) track->st->codec->codec_id = AV_CODEC_ID_MOV_TEXT; else track->st->codec->codec_id = AV_CODEC_ID_TEXT; } break; default: continue; } if (track->st->codec->codec_id == AV_CODEC_ID_MOV_TEXT) { // Build codec extradata for tx3g. // If we were using a libav codec to generate this data // this would (or should) be done for us. uint8_t properties[] = { 0x00, 0x00, 0x00, 0x00, // Display Flags 0x01, // Horiz. Justification 0xff, // Vert. Justification 0x00, 0x00, 0x00, 0xff, // Bg color 0x00, 0x00, 0x00, 0x00, // Default text box 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Reserved 0x00, 0x01, // Font ID 0x00, // Font face 0x18, // Font size 0xff, 0xff, 0xff, 0xff, // Fg color // Font table: 0x00, 0x00, 0x00, 0x12, // Font table size 'f','t','a','b', // Tag 0x00, 0x01, // Count 0x00, 0x01, // Font ID 0x05, // Font name length 'A','r','i','a','l' // Font name }; int width, height = 60; if (job->anamorphic.mode) width = job->width * ((float)job->anamorphic.par_width / job->anamorphic.par_height); else width = job->width; track->st->codec->width = width; track->st->codec->height = height; properties[14] = height >> 8; properties[15] = height & 0xff; properties[16] = width >> 8; properties[17] = width & 0xff; priv_size = sizeof(properties); priv_data = av_malloc(priv_size); if (priv_data == NULL) { hb_error("malloc failure"); goto error; } memcpy(priv_data, properties, priv_size); } track->st->codec->extradata = priv_data; track->st->codec->extradata_size = priv_size; if ( ii == subtitle_default ) { track->st->disposition |= AV_DISPOSITION_DEFAULT; } lang = lookup_lang_code(job->mux, subtitle->iso639_2 ); if (lang != NULL) { av_dict_set(&track->st->metadata, "language", lang, 0); } }
AVStream* AVFormatWriter::AddVideoStream(void) { AVCodecContext *c; AVStream *st; AVCodec *codec; st = avformat_new_stream(m_ctx, NULL); if (!st) { LOG(VB_RECORD, LOG_ERR, LOC + "AddVideoStream(): avformat_new_stream() failed"); return NULL; } st->id = 0; c = st->codec; codec = avcodec_find_encoder(m_ctx->oformat->video_codec); if (!codec) { LOG(VB_RECORD, LOG_ERR, LOC + "AddVideoStream(): avcodec_find_encoder() failed"); return false; } avcodec_get_context_defaults3(c, codec); c->codec = codec; c->codec_id = m_ctx->oformat->video_codec; c->codec_type = AVMEDIA_TYPE_VIDEO; c->bit_rate = m_videoBitrate; c->width = m_width; c->height = m_height; // c->sample_aspect_ratio.num = (int)floor(m_aspect * 10000); // c->sample_aspect_ratio.den = 10000; c->time_base = GetCodecTimeBase(); st->time_base.den = 90000; st->time_base.num = 1; st->r_frame_rate.num = 0; st->r_frame_rate.den = 0; c->gop_size = m_keyFrameDist; c->pix_fmt = PIX_FMT_YUV420P; c->thread_count = m_encodingThreadCount; c->thread_type = FF_THREAD_SLICE; if (c->codec_id == CODEC_ID_MPEG2VIDEO) { c->max_b_frames = 2; } else if (c->codec_id == CODEC_ID_MPEG1VIDEO) { c->mb_decision = 2; } else if (c->codec_id == CODEC_ID_H264) { if ((c->width > 480) || (c->bit_rate > 600000)) { c->level = 31; av_opt_set(c->priv_data, "profile", "main", 0); } else { c->level = 30; av_opt_set(c->priv_data, "profile", "baseline", 0); } c->coder_type = 0; c->max_b_frames = 0; c->slices = 8; c->flags |= CODEC_FLAG_LOOP_FILTER; c->me_cmp |= 1; c->me_method = ME_HEX; c->me_subpel_quality = 6; c->me_range = 16; c->keyint_min = 25; c->scenechange_threshold = 40; c->i_quant_factor = 0.71; c->b_frame_strategy = 1; c->qcompress = 0.6; c->qmin = 10; c->qmax = 51; c->max_qdiff = 4; c->refs = 3; c->trellis = 0; av_opt_set(c, "partitions", "i8x8,i4x4,p8x8,b8x8", 0); av_opt_set_int(c, "direct-pred", 1, 0); av_opt_set_int(c, "rc-lookahead", 0, 0); av_opt_set_int(c, "fast-pskip", 1, 0); av_opt_set_int(c, "mixed-refs", 1, 0); av_opt_set_int(c, "8x8dct", 0, 0); av_opt_set_int(c, "weightb", 0, 0); } if(m_ctx->oformat->flags & AVFMT_GLOBALHEADER) c->flags |= CODEC_FLAG_GLOBAL_HEADER; return st; }
/********************************************************************** * avformatInit ********************************************************************** * Allocates hb_mux_data_t structures, create file and write headers *********************************************************************/ static int avformatInit( hb_mux_object_t * m ) { hb_job_t * job = m->job; hb_audio_t * audio; hb_mux_data_t * track; int meta_mux; int max_tracks; int ii, jj, ret; int clock_min, clock_max, clock; hb_video_framerate_get_limits(&clock_min, &clock_max, &clock); const char *muxer_name = NULL; uint8_t default_track_flag = 1; uint8_t need_fonts = 0; char *lang; max_tracks = 1 + hb_list_count( job->list_audio ) + hb_list_count( job->list_subtitle ); m->tracks = calloc(max_tracks, sizeof(hb_mux_data_t*)); m->oc = avformat_alloc_context(); if (m->oc == NULL) { hb_error( "Could not initialize avformat context." ); goto error; } AVDictionary * av_opts = NULL; switch (job->mux) { case HB_MUX_AV_MP4: m->time_base.num = 1; m->time_base.den = 90000; if( job->ipod_atom ) muxer_name = "ipod"; else muxer_name = "mp4"; meta_mux = META_MUX_MP4; av_dict_set(&av_opts, "brand", "mp42", 0); if (job->mp4_optimize) av_dict_set(&av_opts, "movflags", "faststart+disable_chpl", 0); else av_dict_set(&av_opts, "movflags", "+disable_chpl", 0); break; case HB_MUX_AV_MKV: // libavformat is essentially hard coded such that it only // works with a timebase of 1/1000 m->time_base.num = 1; m->time_base.den = 1000; muxer_name = "matroska"; meta_mux = META_MUX_MKV; break; default: { hb_error("Invalid Mux %x", job->mux); goto error; } } m->oc->oformat = av_guess_format(muxer_name, NULL, NULL); if(m->oc->oformat == NULL) { hb_error("Could not guess output format %s", muxer_name); goto error; } av_strlcpy(m->oc->filename, job->file, sizeof(m->oc->filename)); ret = avio_open2(&m->oc->pb, job->file, AVIO_FLAG_WRITE, &m->oc->interrupt_callback, NULL); if( ret < 0 ) { hb_error( "avio_open2 failed, errno %d", ret); goto error; } /* Video track */ track = m->tracks[m->ntracks++] = calloc(1, sizeof( hb_mux_data_t ) ); job->mux_data = track; track->type = MUX_TYPE_VIDEO; track->prev_chapter_tc = AV_NOPTS_VALUE; track->st = avformat_new_stream(m->oc, NULL); if (track->st == NULL) { hb_error("Could not initialize video stream"); goto error; } track->st->time_base = m->time_base; avcodec_get_context_defaults3(track->st->codec, NULL); track->st->codec->codec_type = AVMEDIA_TYPE_VIDEO; track->st->codec->flags |= CODEC_FLAG_GLOBAL_HEADER; uint8_t *priv_data = NULL; int priv_size = 0; switch (job->vcodec) { case HB_VCODEC_X264_8BIT: case HB_VCODEC_X264_10BIT: case HB_VCODEC_QSV_H264: track->st->codec->codec_id = AV_CODEC_ID_H264; /* Taken from x264 muxers.c */ priv_size = 5 + 1 + 2 + job->config.h264.sps_length + 1 + 2 + job->config.h264.pps_length; priv_data = av_malloc(priv_size + FF_INPUT_BUFFER_PADDING_SIZE); if (priv_data == NULL) { hb_error("H.264 extradata: malloc failure"); goto error; } priv_data[0] = 1; priv_data[1] = job->config.h264.sps[1]; /* AVCProfileIndication */ priv_data[2] = job->config.h264.sps[2]; /* profile_compat */ priv_data[3] = job->config.h264.sps[3]; /* AVCLevelIndication */ priv_data[4] = 0xff; // nalu size length is four bytes priv_data[5] = 0xe1; // one sps priv_data[6] = job->config.h264.sps_length >> 8; priv_data[7] = job->config.h264.sps_length; memcpy(priv_data+8, job->config.h264.sps, job->config.h264.sps_length); priv_data[8+job->config.h264.sps_length] = 1; // one pps priv_data[9+job->config.h264.sps_length] = job->config.h264.pps_length >> 8; priv_data[10+job->config.h264.sps_length] = job->config.h264.pps_length; memcpy(priv_data+11+job->config.h264.sps_length, job->config.h264.pps, job->config.h264.pps_length ); break; case HB_VCODEC_FFMPEG_MPEG4: track->st->codec->codec_id = AV_CODEC_ID_MPEG4; if (job->config.mpeg4.length != 0) { priv_size = job->config.mpeg4.length; priv_data = av_malloc(priv_size + FF_INPUT_BUFFER_PADDING_SIZE); if (priv_data == NULL) { hb_error("MPEG4 extradata: malloc failure"); goto error; } memcpy(priv_data, job->config.mpeg4.bytes, priv_size); } break; case HB_VCODEC_FFMPEG_MPEG2: track->st->codec->codec_id = AV_CODEC_ID_MPEG2VIDEO; if (job->config.mpeg4.length != 0) { priv_size = job->config.mpeg4.length; priv_data = av_malloc(priv_size + FF_INPUT_BUFFER_PADDING_SIZE); if (priv_data == NULL) { hb_error("MPEG2 extradata: malloc failure"); goto error; } memcpy(priv_data, job->config.mpeg4.bytes, priv_size); } break; case HB_VCODEC_FFMPEG_VP8: track->st->codec->codec_id = AV_CODEC_ID_VP8; priv_data = NULL; priv_size = 0; break; case HB_VCODEC_FFMPEG_VP9: track->st->codec->codec_id = AV_CODEC_ID_VP9; priv_data = NULL; priv_size = 0; break; case HB_VCODEC_THEORA: { track->st->codec->codec_id = AV_CODEC_ID_THEORA; int size = 0; ogg_packet *ogg_headers[3]; for (ii = 0; ii < 3; ii++) { ogg_headers[ii] = (ogg_packet *)job->config.theora.headers[ii]; size += ogg_headers[ii]->bytes + 2; } priv_size = size; priv_data = av_malloc(priv_size + FF_INPUT_BUFFER_PADDING_SIZE); if (priv_data == NULL) { hb_error("Theora extradata: malloc failure"); goto error; } size = 0; for(ii = 0; ii < 3; ii++) { AV_WB16(priv_data + size, ogg_headers[ii]->bytes); size += 2; memcpy(priv_data+size, ogg_headers[ii]->packet, ogg_headers[ii]->bytes); size += ogg_headers[ii]->bytes; } } break; case HB_VCODEC_X265_8BIT: case HB_VCODEC_X265_10BIT: case HB_VCODEC_X265_12BIT: case HB_VCODEC_X265_16BIT: case HB_VCODEC_QSV_H265: track->st->codec->codec_id = AV_CODEC_ID_HEVC; if (job->config.h265.headers_length > 0) { priv_size = job->config.h265.headers_length; priv_data = av_malloc(priv_size + FF_INPUT_BUFFER_PADDING_SIZE); if (priv_data == NULL) { hb_error("H.265 extradata: malloc failure"); goto error; } memcpy(priv_data, job->config.h265.headers, priv_size); } break; default: hb_error("muxavformat: Unknown video codec: %x", job->vcodec); goto error; } track->st->codec->extradata = priv_data; track->st->codec->extradata_size = priv_size; track->st->sample_aspect_ratio.num = job->par.num; track->st->sample_aspect_ratio.den = job->par.den; track->st->codec->sample_aspect_ratio.num = job->par.num; track->st->codec->sample_aspect_ratio.den = job->par.den; track->st->codec->width = job->width; track->st->codec->height = job->height; track->st->disposition |= AV_DISPOSITION_DEFAULT; hb_rational_t vrate = job->vrate; // If the vrate is the internal clock rate, there's a good chance // this is a standard rate that we have in our hb_video_rates table. // Because of rounding errors and approximations made while // measuring framerate, the actual value may not be exact. So // we look for rates that are "close" and make an adjustment // to fps.den. if (vrate.num == clock) { const hb_rate_t *video_framerate = NULL; while ((video_framerate = hb_video_framerate_get_next(video_framerate)) != NULL) { if (abs(vrate.den - video_framerate->rate) < 10) { vrate.den = video_framerate->rate; break; } } } hb_reduce(&vrate.num, &vrate.den, vrate.num, vrate.den); if (job->mux == HB_MUX_AV_MP4) { // libavformat mp4 muxer requires that the codec time_base have the // same denominator as the stream time_base, it uses it for the // mdhd timescale. double scale = (double)track->st->time_base.den / vrate.num; track->st->codec->time_base.den = track->st->time_base.den; track->st->codec->time_base.num = vrate.den * scale; } else { track->st->codec->time_base.num = vrate.den; track->st->codec->time_base.den = vrate.num; } track->st->avg_frame_rate.num = vrate.num; track->st->avg_frame_rate.den = vrate.den; /* add the audio tracks */ for(ii = 0; ii < hb_list_count( job->list_audio ); ii++ ) { audio = hb_list_item( job->list_audio, ii ); track = m->tracks[m->ntracks++] = calloc(1, sizeof( hb_mux_data_t ) ); audio->priv.mux_data = track; track->type = MUX_TYPE_AUDIO; track->st = avformat_new_stream(m->oc, NULL); if (track->st == NULL) { hb_error("Could not initialize audio stream"); goto error; } avcodec_get_context_defaults3(track->st->codec, NULL); track->st->codec->codec_type = AVMEDIA_TYPE_AUDIO; track->st->codec->flags |= CODEC_FLAG_GLOBAL_HEADER; if (job->mux == HB_MUX_AV_MP4) { track->st->codec->time_base.num = audio->config.out.samples_per_frame; track->st->codec->time_base.den = audio->config.out.samplerate; track->st->time_base.num = 1; track->st->time_base.den = audio->config.out.samplerate; } else { track->st->codec->time_base = m->time_base; track->st->time_base = m->time_base; } priv_data = NULL; priv_size = 0; switch (audio->config.out.codec & HB_ACODEC_MASK) { case HB_ACODEC_DCA: case HB_ACODEC_DCA_HD: track->st->codec->codec_id = AV_CODEC_ID_DTS; break; case HB_ACODEC_AC3: track->st->codec->codec_id = AV_CODEC_ID_AC3; break; case HB_ACODEC_FFEAC3: track->st->codec->codec_id = AV_CODEC_ID_EAC3; break; case HB_ACODEC_FFTRUEHD: track->st->codec->codec_id = AV_CODEC_ID_TRUEHD; break; case HB_ACODEC_LAME: case HB_ACODEC_MP3: track->st->codec->codec_id = AV_CODEC_ID_MP3; break; case HB_ACODEC_VORBIS: { track->st->codec->codec_id = AV_CODEC_ID_VORBIS; int jj, size = 0; ogg_packet *ogg_headers[3]; for (jj = 0; jj < 3; jj++) { ogg_headers[jj] = (ogg_packet *)audio->priv.config.vorbis.headers[jj]; size += ogg_headers[jj]->bytes + 2; } priv_size = size; priv_data = av_malloc(priv_size + FF_INPUT_BUFFER_PADDING_SIZE); if (priv_data == NULL) { hb_error("Vorbis extradata: malloc failure"); goto error; } size = 0; for(jj = 0; jj < 3; jj++) { AV_WB16(priv_data + size, ogg_headers[jj]->bytes); size += 2; memcpy(priv_data+size, ogg_headers[jj]->packet, ogg_headers[jj]->bytes); size += ogg_headers[jj]->bytes; } } break; case HB_ACODEC_FFFLAC: case HB_ACODEC_FFFLAC24: track->st->codec->codec_id = AV_CODEC_ID_FLAC; if (audio->priv.config.extradata.length) { priv_size = audio->priv.config.extradata.length; priv_data = av_malloc(priv_size + FF_INPUT_BUFFER_PADDING_SIZE); if (priv_data == NULL) { hb_error("FLAC extradata: malloc failure"); goto error; } memcpy(priv_data, audio->priv.config.extradata.bytes, audio->priv.config.extradata.length); } break; case HB_ACODEC_FFAAC: case HB_ACODEC_CA_AAC: case HB_ACODEC_CA_HAAC: case HB_ACODEC_FDK_AAC: case HB_ACODEC_FDK_HAAC: track->st->codec->codec_id = AV_CODEC_ID_AAC; // libav mkv muxer expects there to be extradata for // AAC and will crash if it is NULL. // // Also, libav can over-read the buffer by up to 8 bytes // when it fills it's get_bits cache. // // So allocate extra bytes priv_size = audio->priv.config.extradata.length; priv_data = av_malloc(priv_size + FF_INPUT_BUFFER_PADDING_SIZE); if (priv_data == NULL) { hb_error("AAC extradata: malloc failure"); goto error; } memcpy(priv_data, audio->priv.config.extradata.bytes, audio->priv.config.extradata.length); // AAC from pass-through source may be ADTS. // Therefore inserting "aac_adtstoasc" bitstream filter is // preferred. // The filter does nothing for non-ADTS bitstream. if (audio->config.out.codec == HB_ACODEC_AAC_PASS) { track->bitstream_filter = av_bitstream_filter_init("aac_adtstoasc"); } break; default: hb_error("muxavformat: Unknown audio codec: %x", audio->config.out.codec); goto error; } track->st->codec->extradata = priv_data; track->st->codec->extradata_size = priv_size; if( default_track_flag ) { track->st->disposition |= AV_DISPOSITION_DEFAULT; default_track_flag = 0; } lang = lookup_lang_code(job->mux, audio->config.lang.iso639_2 ); if (lang != NULL) { av_dict_set(&track->st->metadata, "language", lang, 0); } track->st->codec->sample_rate = audio->config.out.samplerate; if (audio->config.out.codec & HB_ACODEC_PASS_FLAG) { track->st->codec->channels = av_get_channel_layout_nb_channels(audio->config.in.channel_layout); track->st->codec->channel_layout = audio->config.in.channel_layout; } else { track->st->codec->channels = hb_mixdown_get_discrete_channel_count(audio->config.out.mixdown); track->st->codec->channel_layout = hb_ff_mixdown_xlat(audio->config.out.mixdown, NULL); } char *name; if (audio->config.out.name == NULL) { switch (track->st->codec->channels) { case 1: name = "Mono"; break; case 2: name = "Stereo"; break; default: name = "Surround"; break; } } else { name = audio->config.out.name; } // Set audio track title av_dict_set(&track->st->metadata, "title", name, 0); if (job->mux == HB_MUX_AV_MP4) { // Some software (MPC, mediainfo) use hdlr description // for track title av_dict_set(&track->st->metadata, "handler", name, 0); } } // Check for audio track associations for (ii = 0; ii < hb_list_count(job->list_audio); ii++) { audio = hb_list_item(job->list_audio, ii); switch (audio->config.out.codec & HB_ACODEC_MASK) { case HB_ACODEC_FFAAC: case HB_ACODEC_CA_AAC: case HB_ACODEC_CA_HAAC: case HB_ACODEC_FDK_AAC: case HB_ACODEC_FDK_HAAC: break; default: { // Mark associated fallback audio tracks for any non-aac track for(jj = 0; jj < hb_list_count( job->list_audio ); jj++ ) { hb_audio_t * fallback; int codec; if (ii == jj) continue; fallback = hb_list_item( job->list_audio, jj ); codec = fallback->config.out.codec & HB_ACODEC_MASK; if (fallback->config.in.track == audio->config.in.track && (codec == HB_ACODEC_FFAAC || codec == HB_ACODEC_CA_AAC || codec == HB_ACODEC_CA_HAAC || codec == HB_ACODEC_FDK_AAC || codec == HB_ACODEC_FDK_HAAC)) { hb_mux_data_t * fallback_track; int * sd; track = audio->priv.mux_data; fallback_track = fallback->priv.mux_data; sd = (int*)av_stream_new_side_data(track->st, AV_PKT_DATA_FALLBACK_TRACK, sizeof(int)); if (sd != NULL) { *sd = fallback_track->st->index; } } } } break; } } char * subidx_fmt = "size: %dx%d\n" "org: %d, %d\n" "scale: 100%%, 100%%\n" "alpha: 100%%\n" "smooth: OFF\n" "fadein/out: 50, 50\n" "align: OFF at LEFT TOP\n" "time offset: 0\n" "forced subs: %s\n" "palette: %06x, %06x, %06x, %06x, %06x, %06x, " "%06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x\n" "custom colors: OFF, tridx: 0000, " "colors: 000000, 000000, 000000, 000000\n"; int subtitle_default = -1; for( ii = 0; ii < hb_list_count( job->list_subtitle ); ii++ ) { hb_subtitle_t *subtitle = hb_list_item( job->list_subtitle, ii ); if( subtitle->config.dest == PASSTHRUSUB ) { if ( subtitle->config.default_track ) subtitle_default = ii; } } // Quicktime requires that at least one subtitle is enabled, // else it doesn't show any of the subtitles. // So check to see if any of the subtitles are flagged to be // the defualt. The default will the the enabled track, else // enable the first track. if (job->mux == HB_MUX_AV_MP4 && subtitle_default == -1) { subtitle_default = 0; } for( ii = 0; ii < hb_list_count( job->list_subtitle ); ii++ ) { hb_subtitle_t * subtitle; uint32_t rgb[16]; char subidx[2048]; int len; subtitle = hb_list_item( job->list_subtitle, ii ); if (subtitle->config.dest != PASSTHRUSUB) continue; track = m->tracks[m->ntracks++] = calloc(1, sizeof( hb_mux_data_t ) ); subtitle->mux_data = track; track->type = MUX_TYPE_SUBTITLE; track->st = avformat_new_stream(m->oc, NULL); if (track->st == NULL) { hb_error("Could not initialize subtitle stream"); goto error; } avcodec_get_context_defaults3(track->st->codec, NULL); track->st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE; track->st->codec->flags |= CODEC_FLAG_GLOBAL_HEADER; track->st->time_base = m->time_base; track->st->codec->time_base = m->time_base; track->st->codec->width = subtitle->width; track->st->codec->height = subtitle->height; priv_data = NULL; priv_size = 0; switch (subtitle->source) { case VOBSUB: { int jj; track->st->codec->codec_id = AV_CODEC_ID_DVD_SUBTITLE; for (jj = 0; jj < 16; jj++) rgb[jj] = hb_yuv2rgb(subtitle->palette[jj]); len = snprintf(subidx, 2048, subidx_fmt, subtitle->width, subtitle->height, 0, 0, "OFF", rgb[0], rgb[1], rgb[2], rgb[3], rgb[4], rgb[5], rgb[6], rgb[7], rgb[8], rgb[9], rgb[10], rgb[11], rgb[12], rgb[13], rgb[14], rgb[15]); priv_size = len + 1; priv_data = av_malloc(priv_size + FF_INPUT_BUFFER_PADDING_SIZE); if (priv_data == NULL) { hb_error("VOBSUB extradata: malloc failure"); goto error; } memcpy(priv_data, subidx, priv_size); } break; case PGSSUB: { track->st->codec->codec_id = AV_CODEC_ID_HDMV_PGS_SUBTITLE; } break; case CC608SUB: case CC708SUB: case TX3GSUB: case SRTSUB: case UTF8SUB: case SSASUB: { if (job->mux == HB_MUX_AV_MP4) { track->st->codec->codec_id = AV_CODEC_ID_MOV_TEXT; } else { track->st->codec->codec_id = AV_CODEC_ID_SSA; need_fonts = 1; if (subtitle->extradata_size) { priv_size = subtitle->extradata_size; priv_data = av_malloc(priv_size + FF_INPUT_BUFFER_PADDING_SIZE); if (priv_data == NULL) { hb_error("SSA extradata: malloc failure"); goto error; } memcpy(priv_data, subtitle->extradata, priv_size); } } } break; default: continue; } if (track->st->codec->codec_id == AV_CODEC_ID_MOV_TEXT) { // Build codec extradata for tx3g. // If we were using a libav codec to generate this data // this would (or should) be done for us. uint8_t properties[] = { 0x00, 0x00, 0x00, 0x00, // Display Flags 0x01, // Horiz. Justification 0xff, // Vert. Justification 0x00, 0x00, 0x00, 0xff, // Bg color 0x00, 0x00, 0x00, 0x00, // Default text box 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Reserved 0x00, 0x01, // Font ID 0x00, // Font face 0x18, // Font size 0xff, 0xff, 0xff, 0xff, // Fg color // Font table: 0x00, 0x00, 0x00, 0x12, // Font table size 'f','t','a','b', // Tag 0x00, 0x01, // Count 0x00, 0x01, // Font ID 0x05, // Font name length 'A','r','i','a','l' // Font name }; int width, height = 60; width = job->width * job->par.num / job->par.den; track->st->codec->width = width; track->st->codec->height = height; properties[14] = height >> 8; properties[15] = height & 0xff; properties[16] = width >> 8; properties[17] = width & 0xff; priv_size = sizeof(properties); priv_data = av_malloc(priv_size + FF_INPUT_BUFFER_PADDING_SIZE); if (priv_data == NULL) { hb_error("TX3G extradata: malloc failure"); goto error; } memcpy(priv_data, properties, priv_size); } track->st->codec->extradata = priv_data; track->st->codec->extradata_size = priv_size; if (ii == subtitle_default) { track->st->disposition |= AV_DISPOSITION_DEFAULT; } if (subtitle->config.default_track) { track->st->disposition |= AV_DISPOSITION_FORCED; } lang = lookup_lang_code(job->mux, subtitle->iso639_2 ); if (lang != NULL) { av_dict_set(&track->st->metadata, "language", lang, 0); } }