Skip to content

Commit

Permalink
feat(decode): Update ffmpeg-decode
Browse files Browse the repository at this point in the history
Signed-off-by: Hakusai Zhang <xm1994@gmail.com>
  • Loading branch information
summershrimp committed Oct 27, 2024
1 parent 4c50701 commit 371e573
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 120 deletions.
29 changes: 10 additions & 19 deletions buildspec.json
Original file line number Diff line number Diff line change
@@ -1,42 +1,33 @@
{
"dependencies": {
"obs-studio": {
"version": "30.0.2",
"version": "30.2.0",
"baseUrl": "https://github.com/obsproject/obs-studio/archive/refs/tags",
"label": "OBS sources",
"hashes": {
"macos": "be12c3ad0a85713750d8325e4b1db75086223402d7080d0e3c2833d7c5e83c27",
"windows-x64": "970058c49322cfa9cd6d620abb393fed89743ba7e74bd9dbb6ebe0ea8141d9c7"
"macos": "a94e585aa9e1c300a9294df80d9370c1d83eb64d9c331002968c6422019821dc",
"windows-x64": "762eaa67162877e2073edd01ce9880b6ae25ccfe971c87d8bec5883fb1f95b7e"
}
},
"prebuilt": {
"version": "2023-11-03",
"version": "2024-05-08",
"baseUrl": "https://github.com/obsproject/obs-deps/releases/download",
"label": "Pre-Built obs-deps",
"hashes": {
"macos": "90c2fc069847ec2768dcc867c1c63b112c615ed845a907dc44acab7a97181974",
"windows-x64": "d0825a6fb65822c993a3059edfba70d72d2e632ef74893588cf12b1f0d329ce6"
}
},
"openssl": {
"version": "2024-01-03",
"baseUrl": "https://github.com/summershrimp/openssl-static/releases/download",
"label": "Pre-Built openssl static",
"hashes": {
"macos": "af7fa1873fa1687ed3b993f240a86d0182e618bc8a8344cd49a56ae5032405ab",
"windows-x64": "0368ed4c82a21b358b6571c21f0a9f0463522466b61a44190f96c351edc7133b"
"macos": "da3167a3efecfa67dd72e4f2b7964c3456d74c639d4c62aa21ec300ebd5007a8",
"windows-x64": "773c87a0d173125ef2768aaca6f6de64a7d6053213cc9f7d3970a301152042d8"
}
},
"qt6": {
"version": "2023-11-03",
"version": "2024-05-08",
"baseUrl": "https://github.com/obsproject/obs-deps/releases/download",
"label": "Pre-Built Qt6",
"hashes": {
"macos": "ba4a7152848da0053f63427a2a2cb0a199af3992997c0db08564df6f48c9db98",
"windows-x64": "bc57dedf76b47119a6dce0435a2f21b35b08c8f2948b1cb34a157320f77732d1"
"macos": "248fb342e7ddf574af0960aaedeffb832deda1485dc81583302646e979593a6e",
"windows-x64": "8f459af5115ce081ae24b108712327e113893f250e14a902b1bd188b43873ed1"
},
"debugSymbols": {
"windows-x64": "fd8ecd1d8cd2ef049d9f4d7fb5c134f784836d6020758094855dfa98bd025036"
"windows-x64": "e4bc882f23195becbe53f1594fe75bdb9ff4f1d01e319f6caf8e0a38000cb42b"
}
}
},
Expand Down
152 changes: 53 additions & 99 deletions src/ffmpeg-decode.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,12 @@
#include <obs-hevc.h>
#endif

#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(58, 4, 100)
#define USE_NEW_HARDWARE_CODEC_METHOD
#endif

#ifdef USE_NEW_HARDWARE_CODEC_METHOD
enum AVHWDeviceType hw_priority[] = {
AV_HWDEVICE_TYPE_QSV, AV_HWDEVICE_TYPE_CUDA,
AV_HWDEVICE_TYPE_DXVA2, AV_HWDEVICE_TYPE_D3D11VA,
AV_HWDEVICE_TYPE_VIDEOTOOLBOX, AV_HWDEVICE_TYPE_NONE};

static bool has_hw_type(AVCodec *c, enum AVHWDeviceType type,
enum AVPixelFormat *hw_pix_fmt)
static bool has_hw_type(const AVCodec *c, enum AVHWDeviceType type)
{
for (int i = 0;; i++) {
const AVCodecHWConfig *config = avcodec_get_hw_config(c, i);
Expand All @@ -43,96 +37,60 @@ static bool has_hw_type(AVCodec *c, enum AVHWDeviceType type,

if (config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX &&
config->device_type == type) {
*hw_pix_fmt = config->pix_fmt;
return true;
}
}
return false;
}

static enum AVPixelFormat get_hw_format(AVCodecContext *ctx,
const enum AVPixelFormat *pix_fmts)
{
const enum AVPixelFormat *p, *t;
enum AVPixelFormat hw_pix_fmt;
struct ffmpeg_decode *d = (struct ffmpeg_decode *)ctx->opaque;
hw_pix_fmt = d->hw_pix_fmt;

for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) {
if (*p == hw_pix_fmt)
return *p;
}
blog(LOG_INFO, "Failed to get HW surface format.\n");
return AV_PIX_FMT_NONE;
}

static void init_hw_decoder(struct ffmpeg_decode *d)
{
enum AVHWDeviceType *priority = hw_priority;
AVBufferRef *hw_ctx = NULL;
enum AVPixelFormat hw_pix_fmt = -1;

while (*priority != AV_HWDEVICE_TYPE_NONE) {
if (has_hw_type(d->codec, *priority, &hw_pix_fmt)) {
if (has_hw_type(d->codec, *priority)) {
int ret = av_hwdevice_ctx_create(&hw_ctx, *priority,
NULL, NULL, 0);
if (ret == 0) {
blog(LOG_INFO, "Use HW type: %u, format %u",
*priority, hw_pix_fmt);
if (ret == 0)
break;
}
}

priority++;
}

if (hw_ctx) {
d->hw_device_ctx = hw_ctx;
d->decoder->hw_device_ctx = av_buffer_ref(hw_ctx);
d->decoder->get_format = get_hw_format;
d->hw_pix_fmt = hw_pix_fmt;
d->hw = true;
}
}
#endif

int ffmpeg_decode_init(struct ffmpeg_decode *decode, enum AVCodecID id,
bool use_hw)
{
int ret;

#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 9, 100)
avcodec_register_all();
#endif
memset(decode, 0, sizeof(*decode));
decode->hw_pix_fmt = AV_PIX_FMT_NONE;

decode->codec = avcodec_find_decoder(id);
if (!decode->codec)
return -1;

decode->decoder = avcodec_alloc_context3(decode->codec);
decode->decoder->opaque = decode;
decode->decoder->thread_count = 2;

decode->decoder->thread_count = 0;
decode->decoder->delay = 0;
//decode->decoder->thread_type = 0;

#ifdef USE_NEW_HARDWARE_CODEC_METHOD
if (use_hw)
init_hw_decoder(decode);
#else
(void)use_hw;
#endif

ret = avcodec_open2(decode->decoder, decode->codec, NULL);
if (ret < 0) {
ffmpeg_decode_free(decode);
return ret;
}

#if LIBAVCODEC_VERSION_MAJOR < 60
if (decode->codec->capabilities & CODEC_CAP_TRUNC)
decode->decoder->flags |= CODEC_FLAG_TRUNC;
#endif

return 0;
}

Expand All @@ -141,14 +99,15 @@ void ffmpeg_decode_free(struct ffmpeg_decode *decode)
if (decode->hw_frame)
av_frame_free(&decode->hw_frame);

if (decode->decoder) {
avcodec_close(decode->decoder);
av_free(decode->decoder);
}
if (decode->decoder)
avcodec_free_context(&decode->decoder);

if (decode->frame)
av_frame_free(&decode->frame);

if (decode->hw_device_ctx)
av_buffer_unref(&decode->hw_device_ctx);

if (decode->packet_buffer)
bfree(decode->packet_buffer);

Expand All @@ -160,6 +119,8 @@ static inline enum video_format convert_pixel_format(int f)
switch (f) {
case AV_PIX_FMT_NONE:
return VIDEO_FORMAT_NONE;
case AV_PIX_FMT_GRAY8:
return VIDEO_FORMAT_Y800;
case AV_PIX_FMT_YUV420P:
case AV_PIX_FMT_YUVJ420P:
return VIDEO_FORMAT_I420;
Expand Down Expand Up @@ -298,8 +259,8 @@ bool ffmpeg_decode_audio(struct ffmpeg_decode *decode, uint8_t *data,

audio->samples_per_sec = decode->frame->sample_rate;
audio->format = convert_sample_format(decode->frame->format);
audio->speakers =
convert_speaker_layout((uint8_t)decode->decoder->channels);
audio->speakers = convert_speaker_layout(
(uint8_t)decode->decoder->ch_layout.nb_channels);

audio->frames = decode->frame->nb_samples;

Expand Down Expand Up @@ -341,31 +302,26 @@ bool ffmpeg_decode_video(struct ffmpeg_decode *decode, uint8_t *data,
struct obs_source_frame2 *frame, bool *got_output)
{
int got_frame = false;

AVFrame *avframe = NULL, *sw_frame = NULL;
AVFrame *tmp_frame = NULL;
uint8_t *buffer = NULL;
int ret = 0;
AVFrame *out_frame;
int ret;

*got_output = false;

copy_data(decode, data, size);

if (!decode->frame) {
decode->frame = av_frame_alloc();
}

if (!decode->hw_frame) {
decode->hw_frame = av_frame_alloc();
}
if (!decode->frame)
return false;

if (!decode->frame || !decode->hw_frame) {
blog(LOG_INFO, "Can not alloc frame\n");
return false;
if (decode->hw && !decode->hw_frame) {
decode->hw_frame = av_frame_alloc();
if (!decode->hw_frame)
return false;
}
}

avframe = decode->hw_frame;
sw_frame = decode->frame;
out_frame = decode->hw ? decode->hw_frame : decode->frame;

AVPacket *packet = av_packet_alloc();
packet->data = decode->packet_buffer;
Expand All @@ -385,42 +341,40 @@ bool ffmpeg_decode_video(struct ffmpeg_decode *decode, uint8_t *data,
}

ret = avcodec_send_packet(decode->decoder, packet);
if (ret < 0) {
blog(LOG_INFO, "Error during decoding\n");
return false;
if (ret == 0) {
ret = avcodec_receive_frame(decode->decoder, out_frame);
}

ret = avcodec_receive_frame(decode->decoder, avframe);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
return true;
} else if (ret < 0) {
blog(LOG_INFO, "Error while decoding\n");
av_packet_free(&packet);

got_frame = (ret == 0);

if (ret == AVERROR_EOF || ret == AVERROR(EAGAIN))
ret = 0;

if (ret < 0)
return false;
}
else if (!got_frame)
return true;

#ifdef USE_NEW_HARDWARE_CODEC_METHOD
if (avframe->format == decode->hw_pix_fmt) {
/* retrieve data from GPU to CPU */
if ((ret = av_hwframe_transfer_data(sw_frame, avframe, 0)) <
0) {
blog(LOG_INFO,
"Error transferring the data to system memory\n");
if (got_frame && decode->hw) {
ret = av_hwframe_transfer_data(decode->frame, out_frame, 0);
if (ret < 0) {
return false;
}
tmp_frame = sw_frame;
} else
#endif
tmp_frame = avframe;
}

for (size_t i = 0; i < MAX_AV_PLANES; i++) {
frame->data[i] = tmp_frame->data[i];
frame->linesize[i] = tmp_frame->linesize[i];
frame->data[i] = decode->frame->data[i];
frame->linesize[i] = decode->frame->linesize[i];
}

frame->format = convert_pixel_format(tmp_frame->format);
const enum video_format format =
convert_pixel_format(decode->frame->format);
frame->format = format;

if (range == VIDEO_RANGE_DEFAULT) {
range = (tmp_frame->color_range == AVCOL_RANGE_JPEG)
range = (decode->frame->color_range == AVCOL_RANGE_JPEG)
? VIDEO_RANGE_FULL
: VIDEO_RANGE_PARTIAL;
}
Expand All @@ -432,8 +386,8 @@ bool ffmpeg_decode_video(struct ffmpeg_decode *decode, uint8_t *data,
}

const bool success = video_format_get_parameters_for_format(
cs, range, frame->format, frame->color_matrix,
frame->color_range_min, frame->color_range_max);
cs, range, format, frame->color_matrix, frame->color_range_min,
frame->color_range_max);
if (!success) {
blog(LOG_ERROR,
"Failed to get video format "
Expand All @@ -444,10 +398,10 @@ bool ffmpeg_decode_video(struct ffmpeg_decode *decode, uint8_t *data,

frame->range = range;

*ts = tmp_frame->pts;
*ts = decode->frame->pts;

frame->width = tmp_frame->width;
frame->height = tmp_frame->height;
frame->width = decode->frame->width;
frame->height = decode->frame->height;
frame->flip = false;

switch (decode->frame->color_trc) {
Expand Down
4 changes: 2 additions & 2 deletions src/ffmpeg-decode.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,13 @@ extern "C" {
#endif

struct ffmpeg_decode {
AVBufferRef *hw_device_ctx;
AVCodecContext *decoder;
AVCodec *codec;
const AVCodec *codec;

AVFrame *hw_frame;
AVFrame *frame;
bool hw;
enum AVPixelFormat hw_pix_fmt;

uint8_t *packet_buffer;
size_t packet_size;
Expand Down

0 comments on commit 371e573

Please sign in to comment.