This commit is contained in:
mofeng-git
2025-12-28 18:19:16 +08:00
commit d143d158e4
771 changed files with 220548 additions and 0 deletions

View File

@@ -0,0 +1,328 @@
// https://github.com/FFmpeg/FFmpeg/blob/master/doc/examples/hw_decode.c
// https://github.com/FFmpeg/FFmpeg/blob/master/doc/examples/decode_video.c
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavutil/log.h>
#include <libavutil/opt.h>
#include <libavutil/pixdesc.h>
}
#include <memory>
#include <stdbool.h>
#define LOG_MODULE "FFMPEG_RAM_DEC"
#include <log.h>
#include <util.h>
#ifdef _WIN32
#include <libavutil/hwcontext_d3d11va.h>
#endif
#include "common.h"
#include "system.h"
// #define CFG_PKG_TRACE
namespace {
typedef void (*RamDecodeCallback)(const void *obj, int width, int height,
enum AVPixelFormat pixfmt,
int linesize[AV_NUM_DATA_POINTERS],
uint8_t *data[AV_NUM_DATA_POINTERS], int key);
class FFmpegRamDecoder {
public:
AVCodecContext *c_ = NULL;
AVBufferRef *hw_device_ctx_ = NULL;
AVFrame *sw_frame_ = NULL;
AVFrame *frame_ = NULL;
AVPacket *pkt_ = NULL;
bool hwaccel_ = true;
std::string name_;
AVHWDeviceType device_type_ = AV_HWDEVICE_TYPE_NONE;
int thread_count_ = 1;
RamDecodeCallback callback_ = NULL;
DataFormat data_format_;
#ifdef CFG_PKG_TRACE
int in_ = 0;
int out_ = 0;
#endif
FFmpegRamDecoder(const char *name, int device_type, int thread_count,
RamDecodeCallback callback) {
this->name_ = name;
this->device_type_ = (AVHWDeviceType)device_type;
this->thread_count_ = thread_count;
this->callback_ = callback;
}
~FFmpegRamDecoder() {}
void free_decoder() {
if (frame_)
av_frame_free(&frame_);
if (pkt_)
av_packet_free(&pkt_);
if (sw_frame_)
av_frame_free(&sw_frame_);
if (c_)
avcodec_free_context(&c_);
if (hw_device_ctx_)
av_buffer_unref(&hw_device_ctx_);
frame_ = NULL;
pkt_ = NULL;
sw_frame_ = NULL;
c_ = NULL;
hw_device_ctx_ = NULL;
}
int reset() {
if (name_.find("h264") != std::string::npos) {
data_format_ = DataFormat::H264;
} else if (name_.find("hevc") != std::string::npos) {
data_format_ = DataFormat::H265;
} else if (name_.find("mjpeg") != std::string::npos) {
data_format_ = DataFormat::MJPEG;
} else {
LOG_ERROR(std::string("unsupported data format:") + name_);
return -1;
}
free_decoder();
const AVCodec *codec = NULL;
hwaccel_ = device_type_ != AV_HWDEVICE_TYPE_NONE;
int ret;
if (!(codec = avcodec_find_decoder_by_name(name_.c_str()))) {
LOG_ERROR(std::string("avcodec_find_decoder_by_name ") + name_ + " failed");
return -1;
}
if (!(c_ = avcodec_alloc_context3(codec))) {
LOG_ERROR(std::string("Could not allocate video codec context"));
return -1;
}
c_->flags |= AV_CODEC_FLAG_LOW_DELAY;
c_->thread_count =
device_type_ != AV_HWDEVICE_TYPE_NONE ? 1 : thread_count_;
c_->thread_type = FF_THREAD_SLICE;
if (name_.find("qsv") != std::string::npos) {
if ((ret = av_opt_set(c_->priv_data, "async_depth", "1", 0)) < 0) {
LOG_ERROR(std::string("qsv set opt async_depth 1 failed"));
return -1;
}
// https://github.com/FFmpeg/FFmpeg/blob/c6364b711bad1fe2fbd90e5b2798f87080ddf5ea/libavcodec/qsvdec.c#L932
// for disable warning
c_->pkt_timebase = av_make_q(1, 30);
}
if (hwaccel_) {
ret =
av_hwdevice_ctx_create(&hw_device_ctx_, device_type_, NULL, NULL, 0);
if (ret < 0) {
LOG_ERROR(std::string("av_hwdevice_ctx_create failed, ret = ") + av_err2str(ret));
return -1;
}
c_->hw_device_ctx = av_buffer_ref(hw_device_ctx_);
if (!check_support()) {
LOG_ERROR(std::string("check_support failed"));
return -1;
}
if (!(sw_frame_ = av_frame_alloc())) {
LOG_ERROR(std::string("av_frame_alloc failed"));
return -1;
}
}
if (!(pkt_ = av_packet_alloc())) {
LOG_ERROR(std::string("av_packet_alloc failed"));
return -1;
}
if (!(frame_ = av_frame_alloc())) {
LOG_ERROR(std::string("av_frame_alloc failed"));
return -1;
}
if ((ret = avcodec_open2(c_, codec, NULL)) != 0) {
LOG_ERROR(std::string("avcodec_open2 failed, ret = ") + av_err2str(ret));
return -1;
}
#ifdef CFG_PKG_TRACE
in_ = 0;
out_ = 0;
#endif
return 0;
}
int decode(const uint8_t *data, int length, const void *obj) {
int ret = -1;
#ifdef CFG_PKG_TRACE
in_++;
LOG_DEBUG(std::string("delay DI: in:") + in_ + " out:" + out_);
#endif
if (!data || !length) {
LOG_ERROR(std::string("illegal decode parameter"));
return -1;
}
pkt_->data = (uint8_t *)data;
pkt_->size = length;
ret = do_decode(obj);
return ret;
}
private:
int do_decode(const void *obj) {
int ret;
AVFrame *tmp_frame = NULL;
bool decoded = false;
ret = avcodec_send_packet(c_, pkt_);
if (ret < 0) {
LOG_ERROR(std::string("avcodec_send_packet failed, ret = ") + av_err2str(ret));
return ret;
}
auto start = util::now();
while (ret >= 0 && util::elapsed_ms(start) < ENCODE_TIMEOUT_MS) {
if ((ret = avcodec_receive_frame(c_, frame_)) != 0) {
if (ret != AVERROR(EAGAIN)) {
LOG_ERROR(std::string("avcodec_receive_frame failed, ret = ") + av_err2str(ret));
}
goto _exit;
}
if (hwaccel_) {
if (!frame_->hw_frames_ctx) {
LOG_ERROR(std::string("hw_frames_ctx is NULL"));
goto _exit;
}
if ((ret = av_hwframe_transfer_data(sw_frame_, frame_, 0)) < 0) {
LOG_ERROR(std::string("av_hwframe_transfer_data failed, ret = ") +
av_err2str(ret));
goto _exit;
}
tmp_frame = sw_frame_;
} else {
tmp_frame = frame_;
}
decoded = true;
#ifdef CFG_PKG_TRACE
out_++;
LOG_DEBUG(std::string("delay DO: in:") + in_ + " out:" + out_);
#endif
#if FF_API_FRAME_KEY
int key_frame = frame_->flags & AV_FRAME_FLAG_KEY;
#else
int key_frame = frame_->key_frame;
#endif
callback_(obj, tmp_frame->width, tmp_frame->height,
(AVPixelFormat)tmp_frame->format, tmp_frame->linesize,
tmp_frame->data, key_frame);
}
_exit:
av_packet_unref(pkt_);
return decoded ? 0 : -1;
}
bool check_support() {
#ifdef _WIN32
if (device_type_ == AV_HWDEVICE_TYPE_D3D11VA) {
if (!c_->hw_device_ctx) {
LOG_ERROR(std::string("hw_device_ctx is NULL"));
return false;
}
AVHWDeviceContext *deviceContext =
(AVHWDeviceContext *)hw_device_ctx_->data;
if (!deviceContext) {
LOG_ERROR(std::string("deviceContext is NULL"));
return false;
}
AVD3D11VADeviceContext *d3d11vaDeviceContext =
(AVD3D11VADeviceContext *)deviceContext->hwctx;
if (!d3d11vaDeviceContext) {
LOG_ERROR(std::string("d3d11vaDeviceContext is NULL"));
return false;
}
ID3D11Device *device = d3d11vaDeviceContext->device;
if (!device) {
LOG_ERROR(std::string("device is NULL"));
return false;
}
std::unique_ptr<NativeDevice> native_ = std::make_unique<NativeDevice>();
if (!native_) {
LOG_ERROR(std::string("Failed to create native device"));
return false;
}
if (!native_->Init(0, (ID3D11Device *)device, 0)) {
LOG_ERROR(std::string("Failed to init native device"));
return false;
}
if (!native_->support_decode(data_format_)) {
LOG_ERROR(std::string("Failed to check support ") + name_);
return false;
}
return true;
} else {
return true;
}
#else
return true;
#endif
}
};
} // namespace
extern "C" void ffmpeg_ram_free_decoder(FFmpegRamDecoder *decoder) {
try {
if (!decoder)
return;
decoder->free_decoder();
delete decoder;
decoder = NULL;
} catch (const std::exception &e) {
LOG_ERROR(std::string("ffmpeg_ram_free_decoder exception:") + e.what());
}
}
extern "C" FFmpegRamDecoder *
ffmpeg_ram_new_decoder(const char *name, int device_type, int thread_count,
RamDecodeCallback callback) {
FFmpegRamDecoder *decoder = NULL;
try {
decoder = new FFmpegRamDecoder(name, device_type, thread_count, callback);
if (decoder) {
if (decoder->reset() == 0) {
return decoder;
}
}
} catch (std::exception &e) {
LOG_ERROR(std::string("new decoder exception:") + e.what());
}
if (decoder) {
decoder->free_decoder();
delete decoder;
decoder = NULL;
}
return NULL;
}
extern "C" int ffmpeg_ram_decode(FFmpegRamDecoder *decoder, const uint8_t *data,
int length, const void *obj) {
try {
int ret = decoder->decode(data, length, obj);
if (DataFormat::H265 == decoder->data_format_ && util_decode::has_flag_could_not_find_ref_with_poc()) {
return HWCODEC_ERR_HEVC_COULD_NOT_FIND_POC;
} else {
return ret == 0 ? HWCODEC_SUCCESS : HWCODEC_ERR_COMMON;
}
} catch (const std::exception &e) {
LOG_ERROR(std::string("ffmpeg_ram_decode exception:") + e.what());
}
return HWCODEC_ERR_COMMON;
}

View File

@@ -0,0 +1,490 @@
// https://github.com/FFmpeg/FFmpeg/blob/master/doc/examples/encode_video.c
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavutil/imgutils.h>
#include <libavutil/log.h>
#include <libavutil/opt.h>
}
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "common.h"
#define LOG_MODULE "FFMPEG_RAM_ENC"
#include <log.h>
#include <util.h>
#ifdef _WIN32
#include "win.h"
#endif
static int calculate_offset_length(int pix_fmt, int height, const int *linesize,
int *offset, int *length) {
switch (pix_fmt) {
case AV_PIX_FMT_YUV420P:
offset[0] = linesize[0] * height;
offset[1] = offset[0] + linesize[1] * height / 2;
*length = offset[1] + linesize[2] * height / 2;
break;
case AV_PIX_FMT_NV12:
offset[0] = linesize[0] * height;
*length = offset[0] + linesize[1] * height / 2;
break;
default:
LOG_ERROR(std::string("unsupported pixfmt") + std::to_string(pix_fmt));
return -1;
}
return 0;
}
extern "C" int ffmpeg_ram_get_linesize_offset_length(int pix_fmt, int width,
int height, int align,
int *linesize, int *offset,
int *length) {
AVFrame *frame = NULL;
int ioffset[AV_NUM_DATA_POINTERS] = {0};
int ilength = 0;
int ret = -1;
if (!(frame = av_frame_alloc())) {
LOG_ERROR(std::string("Alloc frame failed"));
goto _exit;
}
frame->format = pix_fmt;
frame->width = width;
frame->height = height;
if ((ret = av_frame_get_buffer(frame, align)) < 0) {
LOG_ERROR(std::string("av_frame_get_buffer, ret = ") + av_err2str(ret));
goto _exit;
}
if (linesize) {
for (int i = 0; i < AV_NUM_DATA_POINTERS; i++)
linesize[i] = frame->linesize[i];
}
if (offset || length) {
ret = calculate_offset_length(pix_fmt, height, frame->linesize, ioffset,
&ilength);
if (ret < 0)
goto _exit;
}
if (offset) {
for (int i = 0; i < AV_NUM_DATA_POINTERS; i++) {
if (ioffset[i] == 0)
break;
offset[i] = ioffset[i];
}
}
if (length)
*length = ilength;
ret = 0;
_exit:
if (frame)
av_frame_free(&frame);
return ret;
}
namespace {
typedef void (*RamEncodeCallback)(const uint8_t *data, int len, int64_t pts,
int key, const void *obj);
class FFmpegRamEncoder {
public:
AVCodecContext *c_ = NULL;
AVFrame *frame_ = NULL;
AVPacket *pkt_ = NULL;
std::string name_;
std::string mc_name_; // for mediacodec
int width_ = 0;
int height_ = 0;
AVPixelFormat pixfmt_ = AV_PIX_FMT_NV12;
int align_ = 0;
int rc_ = 0;
int quality_ = 0;
int kbs_ = 0;
int q_ = 0;
int fps_ = 30;
int gop_ = 0xFFFF;
int thread_count_ = 1;
int gpu_ = 0;
RamEncodeCallback callback_ = NULL;
int offset_[AV_NUM_DATA_POINTERS] = {0};
bool force_keyframe_ = false; // Force next frame to be a keyframe
AVHWDeviceType hw_device_type_ = AV_HWDEVICE_TYPE_NONE;
AVPixelFormat hw_pixfmt_ = AV_PIX_FMT_NONE;
AVBufferRef *hw_device_ctx_ = NULL;
AVFrame *hw_frame_ = NULL;
FFmpegRamEncoder(const char *name, const char *mc_name, int width, int height,
int pixfmt, int align, int fps, int gop, int rc, int quality,
int kbs, int q, int thread_count, int gpu,
RamEncodeCallback callback) {
name_ = name;
mc_name_ = mc_name ? mc_name : "";
width_ = width;
height_ = height;
pixfmt_ = (AVPixelFormat)pixfmt;
align_ = align;
fps_ = fps;
gop_ = gop;
rc_ = rc;
quality_ = quality;
kbs_ = kbs;
q_ = q;
thread_count_ = thread_count;
gpu_ = gpu;
callback_ = callback;
if (name_.find("vaapi") != std::string::npos) {
hw_device_type_ = AV_HWDEVICE_TYPE_VAAPI;
hw_pixfmt_ = AV_PIX_FMT_VAAPI;
} else if (name_.find("nvenc") != std::string::npos) {
#ifdef _WIN32
hw_device_type_ = AV_HWDEVICE_TYPE_D3D11VA;
hw_pixfmt_ = AV_PIX_FMT_D3D11;
#endif
}
}
~FFmpegRamEncoder() {}
void request_keyframe() {
force_keyframe_ = true;
}
bool init(int *linesize, int *offset, int *length) {
const AVCodec *codec = NULL;
int ret;
if (!(codec = avcodec_find_encoder_by_name(name_.c_str()))) {
LOG_ERROR(std::string("Codec ") + name_ + " not found");
return false;
}
if (!(c_ = avcodec_alloc_context3(codec))) {
LOG_ERROR(std::string("Could not allocate video codec context"));
return false;
}
if (hw_device_type_ != AV_HWDEVICE_TYPE_NONE) {
std::string device = "";
#ifdef _WIN32
if (name_.find("nvenc") != std::string::npos) {
int index = Adapters::GetFirstAdapterIndex(
AdapterVendor::ADAPTER_VENDOR_NVIDIA);
if (index >= 0) {
device = std::to_string(index);
}
}
#endif
ret = av_hwdevice_ctx_create(&hw_device_ctx_, hw_device_type_,
device.length() == 0 ? NULL : device.c_str(),
NULL, 0);
if (ret < 0) {
LOG_ERROR(std::string("av_hwdevice_ctx_create failed"));
return false;
}
if (set_hwframe_ctx() != 0) {
LOG_ERROR(std::string("set_hwframe_ctx failed"));
return false;
}
hw_frame_ = av_frame_alloc();
if (!hw_frame_) {
LOG_ERROR(std::string("av_frame_alloc failed"));
return false;
}
if ((ret = av_hwframe_get_buffer(c_->hw_frames_ctx, hw_frame_, 0)) < 0) {
LOG_ERROR(std::string("av_hwframe_get_buffer failed, ret = ") + av_err2str(ret));
return false;
}
if (!hw_frame_->hw_frames_ctx) {
LOG_ERROR(std::string("hw_frame_->hw_frames_ctx is NULL"));
return false;
}
}
if (!(frame_ = av_frame_alloc())) {
LOG_ERROR(std::string("Could not allocate video frame"));
return false;
}
frame_->format = pixfmt_;
frame_->width = width_;
frame_->height = height_;
if ((ret = av_frame_get_buffer(frame_, align_)) < 0) {
LOG_ERROR(std::string("av_frame_get_buffer failed, ret = ") + av_err2str(ret));
return false;
}
if (!(pkt_ = av_packet_alloc())) {
LOG_ERROR(std::string("Could not allocate video packet"));
return false;
}
/* resolution must be a multiple of two */
c_->width = width_;
c_->height = height_;
c_->pix_fmt =
hw_pixfmt_ != AV_PIX_FMT_NONE ? hw_pixfmt_ : (AVPixelFormat)pixfmt_;
c_->sw_pix_fmt = (AVPixelFormat)pixfmt_;
util_encode::set_av_codec_ctx(c_, name_, kbs_, gop_, fps_);
if (!util_encode::set_lantency_free(c_->priv_data, name_)) {
LOG_ERROR(std::string("set_lantency_free failed, name: ") + name_);
return false;
}
// util_encode::set_quality(c_->priv_data, name_, quality_);
util_encode::set_rate_control(c_, name_, rc_, q_);
util_encode::set_gpu(c_->priv_data, name_, gpu_);
util_encode::force_hw(c_->priv_data, name_);
util_encode::set_others(c_->priv_data, name_);
if (name_.find("mediacodec") != std::string::npos) {
if (mc_name_.length() > 0) {
LOG_INFO(std::string("mediacodec codec_name: ") + mc_name_);
if ((ret = av_opt_set(c_->priv_data, "codec_name", mc_name_.c_str(),
0)) < 0) {
LOG_ERROR(std::string("mediacodec codec_name failed, ret = ") + av_err2str(ret));
}
}
}
if ((ret = avcodec_open2(c_, codec, NULL)) < 0) {
LOG_ERROR(std::string("avcodec_open2 failed, ret = ") + av_err2str(ret) +
", name: " + name_);
return false;
}
if (ffmpeg_ram_get_linesize_offset_length(pixfmt_, width_, height_, align_,
NULL, offset_, length) != 0)
return false;
for (int i = 0; i < AV_NUM_DATA_POINTERS; i++) {
linesize[i] = frame_->linesize[i];
offset[i] = offset_[i];
}
return true;
}
int encode(const uint8_t *data, int length, const void *obj, uint64_t ms) {
int ret;
if ((ret = av_frame_make_writable(frame_)) != 0) {
LOG_ERROR(std::string("av_frame_make_writable failed, ret = ") + av_err2str(ret));
return ret;
}
if ((ret = fill_frame(frame_, (uint8_t *)data, length, offset_)) != 0)
return ret;
AVFrame *tmp_frame;
if (hw_device_type_ != AV_HWDEVICE_TYPE_NONE) {
if ((ret = av_hwframe_transfer_data(hw_frame_, frame_, 0)) < 0) {
LOG_ERROR(std::string("av_hwframe_transfer_data failed, ret = ") + av_err2str(ret));
return ret;
}
tmp_frame = hw_frame_;
} else {
tmp_frame = frame_;
}
return do_encode(tmp_frame, obj, ms);
}
void free_encoder() {
if (pkt_)
av_packet_free(&pkt_);
if (frame_)
av_frame_free(&frame_);
if (hw_frame_)
av_frame_free(&hw_frame_);
if (hw_device_ctx_)
av_buffer_unref(&hw_device_ctx_);
if (c_)
avcodec_free_context(&c_);
}
int set_bitrate(int kbs) {
return util_encode::change_bit_rate(c_, name_, kbs) ? 0 : -1;
}
private:
int set_hwframe_ctx() {
AVBufferRef *hw_frames_ref;
AVHWFramesContext *frames_ctx = NULL;
int err = 0;
if (!(hw_frames_ref = av_hwframe_ctx_alloc(hw_device_ctx_))) {
LOG_ERROR(std::string("av_hwframe_ctx_alloc failed"));
return -1;
}
frames_ctx = (AVHWFramesContext *)(hw_frames_ref->data);
frames_ctx->format = hw_pixfmt_;
frames_ctx->sw_format = (AVPixelFormat)pixfmt_;
frames_ctx->width = width_;
frames_ctx->height = height_;
frames_ctx->initial_pool_size = 1;
if ((err = av_hwframe_ctx_init(hw_frames_ref)) < 0) {
av_buffer_unref(&hw_frames_ref);
return err;
}
c_->hw_frames_ctx = av_buffer_ref(hw_frames_ref);
if (!c_->hw_frames_ctx) {
LOG_ERROR(std::string("av_buffer_ref failed"));
err = -1;
}
av_buffer_unref(&hw_frames_ref);
return err;
}
int do_encode(AVFrame *frame, const void *obj, int64_t ms) {
int ret;
bool encoded = false;
frame->pts = ms;
// Force keyframe if requested
if (force_keyframe_) {
frame->pict_type = AV_PICTURE_TYPE_I;
force_keyframe_ = false;
} else {
frame->pict_type = AV_PICTURE_TYPE_NONE;
}
if ((ret = avcodec_send_frame(c_, frame)) < 0) {
LOG_ERROR(std::string("avcodec_send_frame failed, ret = ") + av_err2str(ret));
return ret;
}
auto start = util::now();
while (ret >= 0 && util::elapsed_ms(start) < DECODE_TIMEOUT_MS) {
if ((ret = avcodec_receive_packet(c_, pkt_)) < 0) {
if (ret != AVERROR(EAGAIN)) {
LOG_ERROR(std::string("avcodec_receive_packet failed, ret = ") + av_err2str(ret));
}
goto _exit;
}
if (!pkt_->data || !pkt_->size) {
LOG_ERROR(std::string("avcodec_receive_packet failed, pkt size is 0"));
goto _exit;
}
encoded = true;
callback_(pkt_->data, pkt_->size, pkt_->pts,
pkt_->flags & AV_PKT_FLAG_KEY, obj);
}
_exit:
av_packet_unref(pkt_);
return encoded ? 0 : -1;
}
int fill_frame(AVFrame *frame, uint8_t *data, int data_length,
const int *const offset) {
switch (frame->format) {
case AV_PIX_FMT_NV12:
if (data_length <
frame->height * (frame->linesize[0] + frame->linesize[1] / 2)) {
LOG_ERROR(std::string("fill_frame: NV12 data length error. data_length:") +
std::to_string(data_length) +
", linesize[0]:" + std::to_string(frame->linesize[0]) +
", linesize[1]:" + std::to_string(frame->linesize[1]));
return -1;
}
frame->data[0] = data;
frame->data[1] = data + offset[0];
break;
case AV_PIX_FMT_YUV420P:
if (data_length <
frame->height * (frame->linesize[0] + frame->linesize[1] / 2 +
frame->linesize[2] / 2)) {
LOG_ERROR(std::string("fill_frame: 420P data length error. data_length:") +
std::to_string(data_length) +
", linesize[0]:" + std::to_string(frame->linesize[0]) +
", linesize[1]:" + std::to_string(frame->linesize[1]) +
", linesize[2]:" + std::to_string(frame->linesize[2]));
return -1;
}
frame->data[0] = data;
frame->data[1] = data + offset[0];
frame->data[2] = data + offset[1];
break;
default:
LOG_ERROR(std::string("fill_frame: unsupported format, ") +
std::to_string(frame->format));
return -1;
}
return 0;
}
};
} // namespace
extern "C" FFmpegRamEncoder *
ffmpeg_ram_new_encoder(const char *name, const char *mc_name, int width,
int height, int pixfmt, int align, int fps, int gop,
int rc, int quality, int kbs, int q, int thread_count,
int gpu, int *linesize, int *offset, int *length,
RamEncodeCallback callback) {
FFmpegRamEncoder *encoder = NULL;
try {
encoder = new FFmpegRamEncoder(name, mc_name, width, height, pixfmt, align,
fps, gop, rc, quality, kbs, q, thread_count,
gpu, callback);
if (encoder) {
if (encoder->init(linesize, offset, length)) {
return encoder;
}
}
} catch (const std::exception &e) {
LOG_ERROR(std::string("new FFmpegRamEncoder failed, ") + std::string(e.what()));
}
if (encoder) {
encoder->free_encoder();
delete encoder;
encoder = NULL;
}
return NULL;
}
extern "C" int ffmpeg_ram_encode(FFmpegRamEncoder *encoder, const uint8_t *data,
int length, const void *obj, uint64_t ms) {
try {
return encoder->encode(data, length, obj, ms);
} catch (const std::exception &e) {
LOG_ERROR(std::string("ffmpeg_ram_encode failed, ") + std::string(e.what()));
}
return -1;
}
extern "C" void ffmpeg_ram_free_encoder(FFmpegRamEncoder *encoder) {
try {
if (!encoder)
return;
encoder->free_encoder();
delete encoder;
encoder = NULL;
} catch (const std::exception &e) {
LOG_ERROR(std::string("free encoder failed, ") + std::string(e.what()));
}
}
extern "C" int ffmpeg_ram_set_bitrate(FFmpegRamEncoder *encoder, int kbs) {
try {
return encoder->set_bitrate(kbs);
} catch (const std::exception &e) {
LOG_ERROR(std::string("ffmpeg_ram_set_bitrate failed, ") + std::string(e.what()));
}
return -1;
}
extern "C" void ffmpeg_ram_request_keyframe(FFmpegRamEncoder *encoder) {
try {
if (encoder) {
encoder->request_keyframe();
}
} catch (const std::exception &e) {
LOG_ERROR(std::string("ffmpeg_ram_request_keyframe failed, ") + std::string(e.what()));
}
}

View File

@@ -0,0 +1,35 @@
#ifndef FFMPEG_RAM_FFI_H
#define FFMPEG_RAM_FFI_H
#include <stdint.h>
#define AV_NUM_DATA_POINTERS 8
typedef void (*RamDecodeCallback)(const void *obj, int width, int height,
int pixfmt,
int linesize[AV_NUM_DATA_POINTERS],
uint8_t *data[AV_NUM_DATA_POINTERS], int key);
typedef void (*RamEncodeCallback)(const uint8_t *data, int len, int64_t pts,
int key, const void *obj);
void *ffmpeg_ram_new_encoder(const char *name, const char *mc_name, int width,
int height, int pixfmt, int align, int fps,
int gop, int rc, int quality, int kbs, int q,
int thread_count, int gpu, int *linesize,
int *offset, int *length,
RamEncodeCallback callback);
void *ffmpeg_ram_new_decoder(const char *name, int device_type,
int thread_count, RamDecodeCallback callback);
int ffmpeg_ram_encode(void *encoder, const uint8_t *data, int length,
const void *obj, int64_t ms);
int ffmpeg_ram_decode(void *decoder, const uint8_t *data, int length,
const void *obj);
void ffmpeg_ram_free_encoder(void *encoder);
void ffmpeg_ram_free_decoder(void *decoder);
int ffmpeg_ram_get_linesize_offset_length(int pix_fmt, int width, int height,
int align, int *linesize, int *offset,
int *length);
int ffmpeg_ram_set_bitrate(void *encoder, int kbs);
void ffmpeg_ram_request_keyframe(void *encoder);
#endif // FFMPEG_RAM_FFI_H