/******************************************************************************** Copyright (C) 2012 Hugh Bailey This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. ********************************************************************************/ #include "Main.h" #include #include extern "C" { #include "../x264/x264.h" } void get_x264_log(void *param, int i_level, const char *psz, va_list argptr) { String chi(psz); chi.FindReplace(TEXT("%s"), TEXT("%S")); OSDebugOutva(chi, argptr); Logva(chi, argptr); } struct VideoPacket { List Packet; inline void FreeData() {Packet.Clear();} }; const float baseCRF = 22.0f; class X264Encoder : public VideoEncoder { x264_param_t paramData; x264_t *x264; x264_picture_t picOut; int cur_pts_time; x264_nal_t *pp_nal; int pi_nal; int fps_ms; UINT width, height; String curPreset; bool bFirstFrameProcessed; bool bUseCBR, bUseCFR; List CurrentPackets; List HeaderPacket; INT64 delayOffset; int frameShift; inline void ClearPackets() { for(UINT i=0; iwidth = width; this->height = height; //warning: messing with x264 settings without knowing what they do can seriously screw things up //ratetol //qcomp //paramData.i_frame_reference = 1; //ref=1 //paramData.i_threads = 4; bUseCBR = AppConfig->GetInt(TEXT("Video Encoding"), TEXT("UseCBR")) != 0; this->bUseCFR = bUseCFR; if(bUseCBR) { paramData.rc.i_bitrate = maxBitRate; paramData.rc.i_vbv_max_bitrate = maxBitRate; //vbv-maxrate paramData.rc.i_vbv_buffer_size = bufferSize; //vbv-bufsize paramData.i_nal_hrd = X264_NAL_HRD_CBR; paramData.rc.i_rc_method = X264_RC_ABR; paramData.rc.f_rf_constant = 0.0f; } else { paramData.rc.i_vbv_max_bitrate = maxBitRate; //vbv-maxrate paramData.rc.i_vbv_buffer_size = bufferSize; //vbv-bufsize paramData.rc.i_rc_method = X264_RC_CRF; paramData.rc.f_rf_constant = baseCRF+float(10-quality); } paramData.b_vfr_input = !bUseCFR; paramData.i_width = width; paramData.i_height = height; //paramData.vui.b_fullrange = 0; //specify full range input levels //paramData.i_keyint_max = fps*4; //keyframe every 4 sec, should make this an option paramData.i_fps_num = fps; paramData.i_fps_den = 1; paramData.i_timebase_num = 1; paramData.i_timebase_den = 1000; //paramData.pf_log = get_x264_log; //paramData.i_log_level = X264_LOG_INFO; BOOL bUseCustomParams = AppConfig->GetInt(TEXT("Video Encoding"), TEXT("UseCustomSettings")); if(bUseCustomParams) { String strCustomParams = AppConfig->GetString(TEXT("Video Encoding"), TEXT("CustomSettings")); strCustomParams.KillSpaces(); if(strCustomParams.IsValid()) { Log(TEXT("Using custom x264 settings: \"%s\""), strCustomParams.Array()); StringList paramList; strCustomParams.GetTokenList(paramList, ' ', FALSE); for(UINT i=0; iPacket); if(bNewPacket) { packetOut.OutputByte((nal.i_type == NAL_SLICE_IDR || nal.i_type == NAL_SEI) ? 0x17 : 0x27); packetOut.OutputByte(1); packetOut.Serialize(timeOffsetAddr, 3); } packetOut.OutputDword(htonl(newPayloadSize)); packetOut.Serialize(nal.p_payload+skipBytes, newPayloadSize); } /*else if(nal.i_type == NAL_SPS) { VideoPacket *newPacket = CurrentPackets.CreateNew(); BufferOutputSerializer headerOut(newPacket->Packet); headerOut.OutputByte(0x17); headerOut.OutputByte(0); headerOut.Serialize(timeOffsetAddr, 3); headerOut.OutputByte(1); headerOut.Serialize(nal.p_payload+5, 3); headerOut.OutputByte(0xff); headerOut.OutputByte(0xe1); headerOut.OutputWord(htons(nal.i_payload-4)); headerOut.Serialize(nal.p_payload+4, nal.i_payload-4); x264_nal_t &pps = nalOut[i+1]; //the PPS always comes after the SPS headerOut.OutputByte(1); headerOut.OutputWord(htons(pps.i_payload-4)); headerOut.Serialize(pps.p_payload+4, pps.i_payload-4); }*/ else continue; switch(nal.i_ref_idc) { case NAL_PRIORITY_DISPOSABLE: packetTypes << PacketType_VideoDisposable; break; case NAL_PRIORITY_LOW: packetTypes << PacketType_VideoLow; break; case NAL_PRIORITY_HIGH: packetTypes << PacketType_VideoHigh; break; case NAL_PRIORITY_HIGHEST: packetTypes << PacketType_VideoHighest; break; } } packets.SetSize(CurrentPackets.Num()); for(UINT i=0; i