static bool new_stream(struct ffmpeg_mux *ffm, AVStream **stream, const char *name, enum AVCodecID *id) { const AVCodecDescriptor *desc = avcodec_descriptor_get_by_name(name); AVCodec *codec; if (!desc) { printf("Couldn't find encoder '%s'\n", name); return false; } *id = desc->id; codec = avcodec_find_encoder(desc->id); if (!codec) { printf("Couldn't create encoder"); return false; } *stream = avformat_new_stream(ffm->output, codec); if (!*stream) { printf("Couldn't create stream for encoder '%s'\n", name); return false; } (*stream)->id = ffm->output->nb_streams-1; return true; }
bool AVDecoder::open() { DPTR_D(AVDecoder); // codec_ctx can't be null for none-ffmpeg based decoders because we may use it's properties in those decoders if (!d.codec_ctx) { qWarning("FFmpeg codec context not ready"); return false; } AVCodec *codec = 0; if (!d.codec_name.isEmpty()) { codec = avcodec_find_decoder_by_name(d.codec_name.toUtf8().constData()); if (!codec) { const AVCodecDescriptor* cd = avcodec_descriptor_get_by_name(d.codec_name.toUtf8().constData()); if (cd) { codec = avcodec_find_decoder(cd->id); } } } else { codec = avcodec_find_decoder(d.codec_ctx->codec_id); } if (!codec) { // TODO: can be null for none-ffmpeg based decoders QString es(tr("No codec could be found for '%1'")); if (d.codec_name.isEmpty()) { es = es.arg(QLatin1String(avcodec_get_name(d.codec_ctx->codec_id))); } else { es = es.arg(d.codec_name); } qWarning() << es; AVError::ErrorCode ec(AVError::CodecError); switch (d.codec_ctx->coder_type) { case AVMEDIA_TYPE_VIDEO: ec = AVError::VideoCodecNotFound; break; case AVMEDIA_TYPE_AUDIO: ec = AVError::AudioCodecNotFound; break; case AVMEDIA_TYPE_SUBTITLE: ec = AVError::SubtitleCodecNotFound; default: break; } emit error(AVError(ec, es)); return false; } // hwa extra init can be here if (!d.open()) { d.close(); return false; } // TODO: skip for none-ffmpeg based decoders d.applyOptionsForDict(); av_opt_set_int(d.codec_ctx, "refcounted_frames", d.enableFrameRef(), 0); // why dict may have no effect? // TODO: only open for ff decoders AV_ENSURE_OK(avcodec_open2(d.codec_ctx, codec, d.options.isEmpty() ? NULL : &d.dict), false); d.is_open = true; return true; }
int mp_codec_to_av_codec_id(const char *codec) { int id = AV_CODEC_ID_NONE; if (codec) { const AVCodecDescriptor *desc = avcodec_descriptor_get_by_name(codec); if (desc) id = desc->id; if (id == AV_CODEC_ID_NONE) { AVCodec *avcodec = avcodec_find_decoder_by_name(codec); if (avcodec) id = avcodec->id; } } return id; }
bool AudioEncoderFFmpegPrivate::open() { if (codec_name.isEmpty()) { // copy ctx from muxer by copyAVCodecContext AVCodec *codec = avcodec_find_encoder(avctx->codec_id); AV_ENSURE_OK(avcodec_open2(avctx, codec, &dict), false); return true; } AVCodec *codec = avcodec_find_encoder_by_name(codec_name.toUtf8().constData()); if (!codec) { const AVCodecDescriptor* cd = avcodec_descriptor_get_by_name(codec_name.toUtf8().constData()); if (cd) { codec = avcodec_find_encoder(cd->id); } } if (!codec) { qWarning() << "Can not find encoder for codec " << codec_name; return false; } if (avctx) { avcodec_free_context(&avctx); avctx = 0; } avctx = avcodec_alloc_context3(codec); // reset format_used to user defined format. important to update default format if format is invalid format_used = format; if (format.sampleRate() <= 0) { if (codec->supported_samplerates) { qDebug("use first supported sample rate: %d", codec->supported_samplerates[0]); format_used.setSampleRate(codec->supported_samplerates[0]); } else { qWarning("sample rate and supported sample rate are not set. use 44100"); format_used.setSampleRate(44100); } } if (format.sampleFormat() == AudioFormat::SampleFormat_Unknown) { if (codec->sample_fmts) { qDebug("use first supported sample format: %d", codec->sample_fmts[0]); format_used.setSampleFormatFFmpeg((int)codec->sample_fmts[0]); } else { qWarning("sample format and supported sample format are not set. use s16"); format_used.setSampleFormat(AudioFormat::SampleFormat_Signed16); } } if (format.channelLayout() == AudioFormat::ChannelLayout_Unsupported) { if (codec->channel_layouts) { qDebug("use first supported channel layout: %lld", codec->channel_layouts[0]); format_used.setChannelLayoutFFmpeg((qint64)codec->channel_layouts[0]); } else { qWarning("channel layout and supported channel layout are not set. use stereo"); format_used.setChannelLayout(AudioFormat::ChannelLayout_Stereo); } } avctx->sample_fmt = (AVSampleFormat)format_used.sampleFormatFFmpeg(); avctx->channel_layout = format_used.channelLayoutFFmpeg(); avctx->channels = format_used.channels(); avctx->sample_rate = format_used.sampleRate(); avctx->bits_per_raw_sample = format_used.bytesPerSample()*8; /// set the time base. TODO avctx->time_base.num = 1; avctx->time_base.den = format_used.sampleRate(); avctx->bit_rate = bit_rate; qDebug() << format_used; av_dict_set(&dict, "strict", "-2", 0); //aac, vorbis applyOptionsForContext(); // avctx->frame_size will be set in avcodec_open2 AV_ENSURE_OK(avcodec_open2(avctx, codec, &dict), false); // from mpv ao_lavc int pcm_hack = 0; int buffer_size = 0; frame_size = avctx->frame_size; if (frame_size <= 1) pcm_hack = av_get_bits_per_sample(avctx->codec_id)/8; if (pcm_hack) { frame_size = 16384; // "enough" buffer_size = frame_size*pcm_hack*format_used.channels()*2+200; } else { buffer_size = frame_size*format_used.bytesPerSample()*format_used.channels()*2+200; } if (buffer_size < FF_MIN_BUFFER_SIZE) buffer_size = FF_MIN_BUFFER_SIZE; buffer.resize(buffer_size); return true; }
bool VideoEncoderFFmpegPrivate::open() { nb_encoded = 0LL; if (codec_name.isEmpty()) { // copy ctx from muxer by copyAVCodecContext AVCodec *codec = avcodec_find_encoder(avctx->codec_id); AV_ENSURE_OK(avcodec_open2(avctx, codec, &dict), false); return true; } AVCodec *codec = avcodec_find_encoder_by_name(codec_name.toUtf8().constData()); if (!codec) { const AVCodecDescriptor* cd = avcodec_descriptor_get_by_name(codec_name.toUtf8().constData()); if (cd) { codec = avcodec_find_encoder(cd->id); } } if (!codec) { qWarning() << "Can not find encoder for codec " << codec_name; return false; } if (avctx) { avcodec_free_context(&avctx); avctx = 0; } avctx = avcodec_alloc_context3(codec); avctx->width = width; // coded_width works, why? avctx->height = height; // reset format_used to user defined format. important to update default format if format is invalid format_used = VideoFormat::Format_Invalid; AVPixelFormat fffmt = (AVPixelFormat)format.pixelFormatFFmpeg(); if (codec->pix_fmts && format.isValid()) { for (int i = 0; codec->pix_fmts[i] != AVPixelFormat(-1); ++i) { if (fffmt == codec->pix_fmts[i]) { format_used = format.pixelFormat(); break; } } } //avctx->sample_aspect_ratio = AVPixelFormat hwfmt = AVPixelFormat(-1); if (av_pix_fmt_desc_get(codec->pix_fmts[0])->flags & AV_PIX_FMT_FLAG_HWACCEL) hwfmt = codec->pix_fmts[0]; bool use_hwctx = false; if (hwfmt != AVPixelFormat(-1)) { #ifdef HAVE_AVHWCTX const AVHWDeviceType dt = fromHWAName(codec_name.section(QChar('_'), -1).toUtf8().constData()); if (dt != AVHWDeviceType(-1)) { use_hwctx = true; avctx->pix_fmt = hwfmt; hw_device_ctx = NULL; AV_ENSURE(av_hwdevice_ctx_create(&hw_device_ctx, dt, hwdev.toLatin1().constData(), NULL, 0), false); avctx->hw_frames_ctx = av_hwframe_ctx_alloc(hw_device_ctx); if (!avctx->hw_frames_ctx) { qWarning("Failed to create hw frame context for '%s'", codec_name.toLatin1().constData()); return false; } // get sw formats const void *hwcfg = NULL; AVHWFramesConstraints *constraints = av_hwdevice_get_hwframe_constraints(hw_device_ctx, hwcfg); const AVPixelFormat* in_fmts = constraints->valid_sw_formats; AVPixelFormat sw_fmt = AVPixelFormat(-1); if (in_fmts) { sw_fmt = in_fmts[0]; while (*in_fmts != AVPixelFormat(-1)) { if (*in_fmts == fffmt) sw_fmt = *in_fmts; sw_fmts.append(*in_fmts); ++in_fmts; } } else { sw_fmt = QTAV_PIX_FMT_C(YUV420P); } av_hwframe_constraints_free(&constraints); format_used = VideoFormat::pixelFormatFromFFmpeg(sw_fmt); // encoder surface pool parameters AVHWFramesContext* hwfs = (AVHWFramesContext*)avctx->hw_frames_ctx->data; hwfs->format = hwfmt; // must the same as avctx->pix_fmt hwfs->sw_format = sw_fmt; // if it's not set, vaapi will choose the last valid_sw_formats, but that's wrong for vaGetImage/DeriveImage. nvenc always need sw_format // hw upload parameters. encoder's hwframes is just for parameter checking, will never be intialized, so we allocate an individual one. hwframes_ref = av_hwframe_ctx_alloc(hw_device_ctx); if (!hwframes_ref) { qWarning("Failed to create hw frame context for uploading '%s'", codec_name.toLatin1().constData()); } else { hwframes = (AVHWFramesContext*)hwframes_ref->data; hwframes->format = hwfmt; } } #endif //HAVE_AVHWCTX } if (!use_hwctx) { // no hw device (videotoolbox, wrong device name etc.), or old ffmpeg // TODO: check frame is hw frame if (hwfmt == AVPixelFormat(-1)) { // sw enc if (format_used == VideoFormat::Format_Invalid) {// requested format is not supported by sw enc if (codec->pix_fmts) { //pix_fmts[0] is always a sw format here qDebug("use first supported pixel format '%d' for sw encoder", codec->pix_fmts[0]); format_used = VideoFormat::pixelFormatFromFFmpeg((int)codec->pix_fmts[0]); } } } else { if (format_used == VideoFormat::Format_Invalid) { // requested format is not supported by hw enc qDebug("use first supported sw pixel format '%d' for hw encoder", codec->pix_fmts[1]); if (codec->pix_fmts && codec->pix_fmts[1] != AVPixelFormat(-1)) format_used = VideoFormat::pixelFormatFromFFmpeg(codec->pix_fmts[1]); } } if (format_used == VideoFormat::Format_Invalid) { qWarning("fallback to yuv420p"); format_used = VideoFormat::Format_YUV420P; } avctx->pix_fmt = (AVPixelFormat)VideoFormat::pixelFormatToFFmpeg(format_used); } if (frame_rate > 0) avctx->time_base = av_d2q(1.0/frame_rate, frame_rate*1001.0+2); else avctx->time_base = av_d2q(1.0/VideoEncoder::defaultFrameRate(), VideoEncoder::defaultFrameRate()*1001.0+2); qDebug("size: %dx%d tbc: %f=%d/%d", width, height, av_q2d(avctx->time_base), avctx->time_base.num, avctx->time_base.den); avctx->bit_rate = bit_rate; //AVDictionary *dict = 0; if(avctx->codec_id == QTAV_CODEC_ID(H264)) { avctx->gop_size = 10; //avctx->max_b_frames = 3;//h264 av_dict_set(&dict, "preset", "fast", 0); //x264 av_dict_set(&dict, "tune", "zerolatency", 0); //x264 //av_dict_set(&dict, "profile", "main", 0); // conflict with vaapi (int values) } if(avctx->codec_id == AV_CODEC_ID_HEVC){ av_dict_set(&dict, "preset", "ultrafast", 0); av_dict_set(&dict, "tune", "zero-latency", 0); } if (avctx->codec_id == AV_CODEC_ID_MPEG2VIDEO) { av_dict_set(&dict, "strict", "-2", 0); // mpeg2 arbitrary fps } applyOptionsForContext(); AV_ENSURE_OK(avcodec_open2(avctx, codec, &dict), false); // from mpv ao_lavc const int buffer_size = qMax<int>(qMax<int>(width*height*6+200, FF_MIN_BUFFER_SIZE), sizeof(AVPicture));//?? buffer.resize(buffer_size); return true; }
bool AVIDump::CreateVideoFile() { const std::string& format = g_Config.sDumpFormat; const std::string dump_path = GetDumpPath(format); if (dump_path.empty()) return false; File::CreateFullPath(dump_path); AVOutputFormat* output_format = av_guess_format(format.c_str(), dump_path.c_str(), nullptr); if (!output_format) { ERROR_LOG(VIDEO, "Invalid format %s", format.c_str()); return false; } if (avformat_alloc_output_context2(&s_format_context, output_format, nullptr, dump_path.c_str()) < 0) { ERROR_LOG(VIDEO, "Could not allocate output context"); return false; } const std::string& codec_name = g_Config.bUseFFV1 ? "ffv1" : g_Config.sDumpCodec; AVCodecID codec_id = output_format->video_codec; if (!codec_name.empty()) { const AVCodecDescriptor* codec_desc = avcodec_descriptor_get_by_name(codec_name.c_str()); if (codec_desc) codec_id = codec_desc->id; else WARN_LOG(VIDEO, "Invalid codec %s", codec_name.c_str()); } const AVCodec* codec = nullptr; if (!g_Config.sDumpEncoder.empty()) { codec = avcodec_find_encoder_by_name(g_Config.sDumpEncoder.c_str()); if (!codec) WARN_LOG(VIDEO, "Invalid encoder %s", g_Config.sDumpEncoder.c_str()); } if (!codec) codec = avcodec_find_encoder(codec_id); s_codec_context = avcodec_alloc_context3(codec); if (!codec || !s_codec_context) { ERROR_LOG(VIDEO, "Could not find encoder or allocate codec context"); return false; } // Force XVID FourCC for better compatibility if (codec->id == AV_CODEC_ID_MPEG4) s_codec_context->codec_tag = MKTAG('X', 'V', 'I', 'D'); s_codec_context->codec_type = AVMEDIA_TYPE_VIDEO; s_codec_context->bit_rate = g_Config.iBitrateKbps * 1000; s_codec_context->width = s_width; s_codec_context->height = s_height; s_codec_context->time_base.num = 1; s_codec_context->time_base.den = VideoInterface::GetTargetRefreshRate(); s_codec_context->gop_size = 12; s_codec_context->pix_fmt = g_Config.bUseFFV1 ? AV_PIX_FMT_BGRA : AV_PIX_FMT_YUV420P; if (output_format->flags & AVFMT_GLOBALHEADER) s_codec_context->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; if (avcodec_open2(s_codec_context, codec, nullptr) < 0) { ERROR_LOG(VIDEO, "Could not open codec"); return false; } s_src_frame = av_frame_alloc(); s_scaled_frame = av_frame_alloc(); s_scaled_frame->format = s_codec_context->pix_fmt; s_scaled_frame->width = s_width; s_scaled_frame->height = s_height; #if LIBAVCODEC_VERSION_MAJOR >= 55 if (av_frame_get_buffer(s_scaled_frame, 1)) return false; #else if (avcodec_default_get_buffer(s_codec_context, s_scaled_frame)) return false; #endif s_stream = avformat_new_stream(s_format_context, codec); if (!s_stream || !AVStreamCopyContext(s_stream, s_codec_context)) { ERROR_LOG(VIDEO, "Could not create stream"); return false; } NOTICE_LOG(VIDEO, "Opening file %s for dumping", s_format_context->filename); if (avio_open(&s_format_context->pb, s_format_context->filename, AVIO_FLAG_WRITE) < 0 || avformat_write_header(s_format_context, nullptr)) { ERROR_LOG(VIDEO, "Could not open %s", s_format_context->filename); return false; } OSD::AddMessage(StringFromFormat("Dumping Frames to \"%s\" (%dx%d)", s_format_context->filename, s_width, s_height)); return true; }
int groove_encoder_attach(struct GrooveEncoder *encoder, struct GroovePlaylist *playlist) { struct GrooveEncoderPrivate *e = (struct GrooveEncoderPrivate *) encoder; encoder->playlist = playlist; groove_queue_reset(e->audioq); e->oformat = av_guess_format(encoder->format_short_name, encoder->filename, encoder->mime_type); if (!e->oformat) { groove_encoder_detach(encoder); av_log(NULL, AV_LOG_ERROR, "unable to determine format\n"); return -1; } // av_guess_codec ignores mime_type, filename, and codec_short_name. see // https://trac.ffmpeg.org/ticket/4706 // because of this we do a workaround to return the correct codec based on // the codec_short_name. AVCodec *codec = NULL; if (encoder->codec_short_name) { codec = avcodec_find_encoder_by_name(encoder->codec_short_name); if (!codec) { const AVCodecDescriptor *desc = avcodec_descriptor_get_by_name(encoder->codec_short_name); if (desc) { codec = avcodec_find_encoder(desc->id); } } } if (!codec) { enum AVCodecID codec_id = av_guess_codec(e->oformat, encoder->codec_short_name, encoder->filename, encoder->mime_type, AVMEDIA_TYPE_AUDIO); codec = avcodec_find_encoder(codec_id); if (!codec) { groove_encoder_detach(encoder); av_log(NULL, AV_LOG_ERROR, "unable to find encoder\n"); return -1; } } e->codec = codec; av_log(NULL, AV_LOG_INFO, "encoder: using codec: %s\n", codec->long_name); encoder->actual_audio_format.sample_fmt = closest_supported_sample_fmt( codec, encoder->target_audio_format.sample_fmt); encoder->actual_audio_format.sample_rate = closest_supported_sample_rate( codec, encoder->target_audio_format.sample_rate); encoder->actual_audio_format.channel_layout = closest_supported_channel_layout( codec, encoder->target_audio_format.channel_layout); log_audio_fmt(&encoder->actual_audio_format); int err = init_avcontext(encoder); if (err < 0) { groove_encoder_detach(encoder); return err; } e->sink->audio_format = encoder->actual_audio_format; e->sink->buffer_size = encoder->sink_buffer_size; e->sink->buffer_sample_count = (codec->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE) ? 0 : e->stream->codec->frame_size; e->sink->gain = encoder->gain; if (groove_sink_attach(e->sink, playlist) < 0) { groove_encoder_detach(encoder); av_log(NULL, AV_LOG_ERROR, "unable to attach sink\n"); return -1; } if (pthread_create(&e->thread_id, NULL, encode_thread, encoder) != 0) { groove_encoder_detach(encoder); av_log(NULL, AV_LOG_ERROR, "unable to create encoder thread\n"); return -1; } return 0; }
bool VideoEncoderFFmpegPrivate::open() { nb_encoded = 0LL; if (codec_name.isEmpty()) { // copy ctx from muxer by copyAVCodecContext AVCodec *codec = avcodec_find_encoder(avctx->codec_id); AV_ENSURE_OK(avcodec_open2(avctx, codec, &dict), false); return true; } AVCodec *codec = avcodec_find_encoder_by_name(codec_name.toUtf8().constData()); if (!codec) { const AVCodecDescriptor* cd = avcodec_descriptor_get_by_name(codec_name.toUtf8().constData()); if (cd) { codec = avcodec_find_encoder(cd->id); } } if (!codec) { qWarning() << "Can not find encoder for codec " << codec_name; return false; } if (avctx) { avcodec_free_context(&avctx); avctx = 0; } avctx = avcodec_alloc_context3(codec); avctx->width = width; // coded_width works, why? avctx->height = height; // reset format_used to user defined format. important to update default format if format is invalid format_used = format.pixelFormat(); if (format.pixelFormat() == VideoFormat::Format_Invalid) { if (codec->pix_fmts) { qDebug("use first supported pixel format: %d", codec->pix_fmts[0]); format_used = VideoFormat::pixelFormatFromFFmpeg((int)codec->pix_fmts[0]); } else { qWarning("pixel format and supported pixel format are not set. use yuv420p"); format_used = VideoFormat::Format_YUV420P; } } //avctx->sample_aspect_ratio = avctx->pix_fmt = (AVPixelFormat)VideoFormat::pixelFormatToFFmpeg(format_used); if (frame_rate > 0) avctx->time_base = av_d2q(1.0/frame_rate, frame_rate*1001.0+2); else avctx->time_base = av_d2q(1.0/VideoEncoder::defaultFrameRate(), VideoEncoder::defaultFrameRate()*1001.0+2); qDebug("size: %dx%d tbc: %f=%d/%d", width, height, av_q2d(avctx->time_base), avctx->time_base.num, avctx->time_base.den); avctx->bit_rate = bit_rate; #if 1 //AVDictionary *dict = 0; if(avctx->codec_id == QTAV_CODEC_ID(H264)) { avctx->gop_size = 10; //avctx->max_b_frames = 3;//h264 av_dict_set(&dict, "preset", "fast", 0); av_dict_set(&dict, "tune", "zerolatency", 0); av_dict_set(&dict, "profile", "main", 0); } #ifdef FF_PROFILE_HEVC_MAIN if(avctx->codec_id == AV_CODEC_ID_HEVC){ av_dict_set(&dict, "preset", "ultrafast", 0); av_dict_set(&dict, "tune", "zero-latency", 0); } #endif //FF_PROFILE_HEVC_MAIN #endif applyOptionsForContext(); AV_ENSURE_OK(avcodec_open2(avctx, codec, &dict), false); // from mpv ao_lavc const int buffer_size = qMax<int>(qMax<int>(width*height*6+200, FF_MIN_BUFFER_SIZE), sizeof(AVPicture));//?? buffer.resize(buffer_size); return true; }