Skip to content

Commit

Permalink
Added libx264 library, change to default h264 codec
Browse files Browse the repository at this point in the history
  • Loading branch information
Keukhan committed Oct 16, 2024
1 parent 17d8fe6 commit f37ed41
Show file tree
Hide file tree
Showing 8 changed files with 315 additions and 45 deletions.
36 changes: 35 additions & 1 deletion misc/prerequisites.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,16 @@ PCRE2_VERSION=10.39
OPENH264_VERSION=2.4.0
HIREDIS_VERSION=1.0.2
NVCC_HDR_VERSION=11.1.5.2
X264_VERSION=20191217-2245-stable

INTEL_QSV_HWACCELS=false
NETINT_LOGAN_HWACCELS=false
NETINT_LOGAN_PATCH_PATH=""
NETINT_LOGAN_XCODER_COMPILE_PATH=""
NVIDIA_NV_CODEC_HWACCELS=false
XILINX_XMA_CODEC_HWACCELS=false
VIDEOLAN_X264_CODEC=true


if [[ "$OSTYPE" == "darwin"* ]]; then
NCPU=$(sysctl -n hw.ncpu)
Expand Down Expand Up @@ -101,6 +104,22 @@ install_libopus()
rm -rf ${DIR}) || fail_exit "opus"
}

install_libx264()
{
if [ "$VIDEOLAN_X264_CODEC" = false ] ; then
return
fi

(DIR=${TEMP_PATH}/x264 && \
mkdir -p ${DIR} && \
cd ${DIR} && \
curl -sLf https://download.videolan.org/pub/videolan/x264/snapshots/x264-snapshot-${X264_VERSION}.tar.bz2 | tar -jx --strip-components=1 && \

This comment has been minimized.

Copy link
@hashworks

hashworks Oct 18, 2024

Contributor

Are you sure that folder is maintained? Revision 2245 is quite old, current one is 3194. Sadly videolan does not provide proper versioning for x264, I guess you need to check https://artifacts.videolan.org/x264/release-debian-amd64/ and use the noted commit hash: https://code.videolan.org/videolan/x264/-/archive/master/x264-1243d9f.tar.bz2

./configure --prefix="${PREFIX}" --enable-shared --enable-pic --disable-cli && \
make -j$(nproc) && \
sudo make install && \
rm -rf ${DIR}) || fail_exit "x264"
}

install_libopenh264()
{
(DIR=${TEMP_PATH}/openh264 && \
Expand Down Expand Up @@ -254,6 +273,12 @@ install_ffmpeg()
ADDI_EXTRA_LIBS+="--extra-libs=-lxma2api --extra-libs=-lxrt_core --extra-libs=-lxrm --extra-libs=-lxrt_coreutil --extra-libs=-lpthread --extra-libs=-ldl "
fi

if [ "$VIDEOLAN_X264_CODEC" == true ]; then
ADDI_LIBS+=" --enable-libx264 "
ADDI_ENCODER+=",libx264"
ADDI_LICENSE+=" --enable-gpl --enable-nonfree "
fi

# Options are added by external scripts.
if [[ -n "${EXT_FFMPEG_LICENSE}" ]]; then
ADDI_LICENSE+=${EXT_FFMPEG_LICENSE}
Expand Down Expand Up @@ -512,7 +537,15 @@ case $i in
--enable-xma)
XILINX_XMA_CODEC_HWACCELS=true
shift
;;
;;
--disable-x264)
VIDEOLAN_X264_CODEC=false
shift
;;
--enable-x264)
VIDEOLAN_X264_CODEC=true
shift
;;
*)
# unknown option
;;
Expand Down Expand Up @@ -560,6 +593,7 @@ install_libsrtp
install_libsrt
install_libopus
install_libopenh264
install_libx264
install_libvpx
install_fdk_aac
install_nvcc_hdr
Expand Down
52 changes: 26 additions & 26 deletions src/projects/base/mediarouter/media_type.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ namespace cmn
DEFAULT, // SW
OPENH264, // SW
BEAMR, // SW
X264, // SW
NVENC, // HW
QSV, // HW
XMA, // HW
Expand Down Expand Up @@ -250,7 +251,7 @@ namespace cmn
{
return cmn::MediaCodecModuleId::BEAMR;
}
else if (name.HasSuffix("_NVENC") || name.HasSuffix("NV") || name.HasSuffix("NVENC"))
else if (name.HasSuffix("_NVENC") || name.HasSuffix("_NV") || name.HasSuffix("NV") || name.HasSuffix("NVENC"))
{
return cmn::MediaCodecModuleId::NVENC;
}
Expand All @@ -274,6 +275,10 @@ namespace cmn
{
return cmn::MediaCodecModuleId::FDKAAC;
}
else if (name.HasSuffix("_X264") || name.HasSuffix("X264") )
{
return cmn::MediaCodecModuleId::X264;
}
else if (name.HasSuffix("_DEFAULT") || name.HasSuffix("DEFAULT"))
{
return cmn::MediaCodecModuleId::DEFAULT;
Expand Down Expand Up @@ -306,6 +311,8 @@ namespace cmn
return "fdkaac";
case cmn::MediaCodecModuleId::LIBOPUS:
return "libopus";
case cmn::MediaCodecModuleId::X264:
return "x264";
case cmn::MediaCodecModuleId::None:
default:
break;
Expand Down Expand Up @@ -334,6 +341,7 @@ namespace cmn
{
switch (id)
{
// Video codecs
case cmn::MediaCodecId::H264:
return "H264";
case cmn::MediaCodecId::H265:
Expand All @@ -342,16 +350,19 @@ namespace cmn
return "VP8";
case cmn::MediaCodecId::Vp9:
return "VP9";
case cmn::MediaCodecId::Flv:
return "FLV";
case cmn::MediaCodecId::Jpeg:
return "JPEG";
case cmn::MediaCodecId::Png:
return "PNG";
// Audio codecs
case cmn::MediaCodecId::Aac:
return "AAC";
case cmn::MediaCodecId::Mp3:
return "MP3";
case cmn::MediaCodecId::Opus:
return "OPUS";
case cmn::MediaCodecId::Jpeg:
return "JPEG";
case cmn::MediaCodecId::Png:
return "PNG";
default:
break;
}
Expand All @@ -364,55 +375,44 @@ namespace cmn
name.MakeUpper();

// Video codecs
if (name == "H264" ||
name == "H264_OPENH264" ||
name == "H264_BEAMR" ||
name == "H264_NVENC" ||
name == "H264_QSV" ||
name == "H264_NILOGAN" ||
name == "H264_XMA")
if (name.HasPrefix("H264"))
{
return cmn::MediaCodecId::H264;
}
else if (name == "H265" ||
name == "H265_NVENC" ||
name == "H265_QSV" ||
name == "H265_NILOGAN" ||
name == "H265_XMA")
else if (name.HasPrefix("H265"))
{
return cmn::MediaCodecId::H265;
}
else if (name == "VP8")
else if (name.HasPrefix("VP8"))
{
return cmn::MediaCodecId::Vp8;
}
else if (name == "VP9")
else if (name.HasPrefix("VP9"))
{
return cmn::MediaCodecId::Vp9;
}
else if (name == "FLV")
else if (name.HasPrefix("FLV"))
{
return cmn::MediaCodecId::Flv;
}
else if (name == "JPEG")
else if (name.HasPrefix("JPEG"))
{
return cmn::MediaCodecId::Jpeg;
}
else if (name == "PNG")
else if (name.HasPrefix("PNG"))
{
return cmn::MediaCodecId::Png;
}

// Audio codecs
if (name == "AAC")
if (name.HasPrefix("AAC"))
{
return cmn::MediaCodecId::Aac;
}
else if (name == "MP3")
else if (name.HasPrefix("MP3"))
{
return cmn::MediaCodecId::Mp3;
}
else if (name == "OPUS")
else if (name.HasPrefix("OPUS"))
{
return cmn::MediaCodecId::Opus;
}
Expand Down
162 changes: 162 additions & 0 deletions src/projects/transcoder/codec/encoder/encoder_avc_x264.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
//==============================================================================
//
// Transcoder
//
// Created by Kwon Keuk Han
// Copyright (c) 2018 AirenSoft. All rights reserved.
//
//==============================================================================
#include "encoder_avc_x264.h"

#include <unistd.h>

#include "../../transcoder_private.h"


bool EncoderAVCx264::SetCodecParams()
{
_codec_context->bit_rate = GetRefTrack()->GetBitrate();
_codec_context->rc_min_rate = _codec_context->rc_max_rate = _codec_context->bit_rate;
_codec_context->rc_buffer_size = static_cast<int>(_codec_context->bit_rate / 2);
_codec_context->framerate = ::av_d2q((GetRefTrack()->GetFrameRateByConfig() > 0) ? GetRefTrack()->GetFrameRateByConfig() : GetRefTrack()->GetEstimateFrameRate(), AV_TIME_BASE);
_codec_context->sample_aspect_ratio = ::av_make_q(1, 1);

// From avcodec.h:
// For some codecs, the time base is closer to the field rate than the frame rate.
// Most notably, H.264 and MPEG-2 specify time_base as half of frame duration
// if no telecine is used ...
// Set to time_base ticks per frame. Default 1, e.g., H.264/MPEG-2 set it to 2.
_codec_context->ticks_per_frame = 2;

// From avcodec.h:
// For fixed-fps content, timebase should be 1/framerate and timestamp increments should be identically 1.
// This often, but not always is the inverse of the frame rate or field rate for video. 1/time_base is not the average frame rate if the frame rate is not constant.
_codec_context->time_base = (AVRational){GetRefTrack()->GetTimeBase().GetNum(), GetRefTrack()->GetTimeBase().GetDen()};
_codec_context->max_b_frames = GetRefTrack()->GetBFrames();
_codec_context->pix_fmt = (AVPixelFormat)GetSupportedFormat();
_codec_context->width = GetRefTrack()->GetWidth();
_codec_context->height = GetRefTrack()->GetHeight();

// Keyframe Interval
//@see transcoder_encoder.cpp / force_keyframe_by_time_interval
auto key_frame_interval_type = GetRefTrack()->GetKeyFrameIntervalTypeByConfig();
if (key_frame_interval_type == cmn::KeyFrameIntervalType::TIME)
{
_codec_context->gop_size = (int32_t)(GetRefTrack()->GetFrameRate() * (double)GetRefTrack()->GetKeyFrameInterval() / 1000 * 2);
}
else if (key_frame_interval_type == cmn::KeyFrameIntervalType::FRAME)
{
_codec_context->gop_size = (GetRefTrack()->GetKeyFrameInterval() == 0) ? (_codec_context->framerate.num / _codec_context->framerate.den) : GetRefTrack()->GetKeyFrameInterval();
}

// -1(Default) => FFMIN(FFMAX(4, av_cpu_count() / 3), 8)
// 0 => Auto
// >1 => Set
_codec_context->thread_count = GetRefTrack()->GetThreadCount() < 0 ? FFMIN(FFMAX(4, av_cpu_count() / 3), 8) : GetRefTrack()->GetThreadCount();

// Preset
if (GetRefTrack()->GetPreset() == "slower")
{
::av_opt_set(_codec_context->priv_data, "preset", "slower", 0);
}
else if (GetRefTrack()->GetPreset() == "slow")
{
::av_opt_set(_codec_context->priv_data, "preset", "slow", 0);
}
else if (GetRefTrack()->GetPreset() == "medium")
{
::av_opt_set(_codec_context->priv_data, "preset", "medium", 0);
}
else if (GetRefTrack()->GetPreset() == "fast")
{
::av_opt_set(_codec_context->priv_data, "preset", "fast", 0);
}
else if (GetRefTrack()->GetPreset() == "faster")
{
::av_opt_set(_codec_context->priv_data, "preset", "faster", 0);
}
else
{
// Default
::av_opt_set(_codec_context->priv_data, "preset", "faster", 0);
}

// Profile
::av_opt_set(_codec_context->priv_data, "profile", "main", 0);

// Tune
::av_opt_set(_codec_context->priv_data, "tune", "zerolatency", 0);

// Remove the sliced-thread option from encoding delay. Browser compatibility in MAC environment
::av_opt_set(_codec_context->priv_data, "x264opts",
ov::String::FormatString(
"bframes=%d:sliced-threads=0:b-adapt=1:no-scenecut:keyint=%d:min-keyint=%d",
GetRefTrack()->GetBFrames(),
_codec_context->gop_size,
_codec_context->gop_size)
.CStr(),
0);

_bitstream_format = cmn::BitstreamFormat::H264_ANNEXB;

_packet_type = cmn::PacketType::NALU;

return true;
}

// Notes.
//
// - B-frame must be disabled. because, WEBRTC does not support B-Frame.
//
bool EncoderAVCx264::Configure(std::shared_ptr<MediaTrack> context)
{
if (TranscodeEncoder::Configure(context) == false)
{
return false;
}

auto codec_id = GetCodecID();

const AVCodec *codec = ::avcodec_find_encoder_by_name("libx264");
if (codec == nullptr)
{
logte("Could not find encoder: %s (%d)", ::avcodec_get_name(codec_id), codec_id);
return false;
}

_codec_context = ::avcodec_alloc_context3(codec);
if (_codec_context == nullptr)
{
logte("Could not allocate codec context for %s (%d)", ::avcodec_get_name(GetCodecID()), GetCodecID());
return false;
}

if (SetCodecParams() == false)
{
logte("Could not set codec parameters for %s (%d)", ::avcodec_get_name(GetCodecID()), GetCodecID());
return false;
}
if (::avcodec_open2(_codec_context, _codec_context->codec, nullptr) < 0)
{
logte("Could not open codec: %s (%d)", ::avcodec_get_name(GetCodecID()), GetCodecID());
return false;
}

// Generates a thread that reads and encodes frames in the input_buffer queue and places them in the output queue.
try
{
_kill_flag = false;

_codec_thread = std::thread(&EncoderAVCx264::CodecThread, this);
pthread_setname_np(_codec_thread.native_handle(), ov::String::FormatString("Enc%s", avcodec_get_name(GetCodecID())).CStr());
}
catch (const std::system_error &e)
{
logte("Failed to start encoder thread.");
_kill_flag = true;

return false;
}

return true;
}
Loading

0 comments on commit f37ed41

Please sign in to comment.