Skip to content

Commit

Permalink
Merge pull request #5 from Quicr/h264
Browse files Browse the repository at this point in the history
h264 2-way video work, but no color
  • Loading branch information
suhasHere committed Mar 16, 2022
2 parents fff41de + fa5f253 commit 1eb170a
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 60 deletions.
2 changes: 1 addition & 1 deletion include/h264_encoder.hh
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public:
const unsigned int mtu_size = 1300;

ISVCEncoder *encoder{};
SEncParamExt encodeParams;
SEncParamBase encParamBase;
SFrameBSInfo outputFrame{};
SSourcePicture inputFrame{};
};
Expand Down
81 changes: 67 additions & 14 deletions src/h264_decoder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,18 @@
#include <iostream>
#include <vector>
#include <cassert>
#include <fstream>
#include <stdio.h>

#include <string.h> // memcpy , strncat

#include "h264_decoder.hh"

using namespace neo_media;
using namespace std;

FILE* video_input;
FILE* video_output;

H264Decoder::H264Decoder(std::uint32_t video_pixel_format)
{
Expand All @@ -25,7 +31,6 @@ H264Decoder::H264Decoder(std::uint32_t video_pixel_format)
dec_param.eEcActiveIdc = ERROR_CON_SLICE_MV_COPY_CROSS_IDR_FREEZE_RES_CHANGE;
dec_param.sVideoProperty.size = sizeof(SVideoProperty);
dec_param.sVideoProperty.eVideoBsType = VIDEO_BITSTREAM_AVC;
// dec_param.sVideoProperty.eVideoBsType = VIDEO_BITSTREAM_SVC;

ret = decoder->Initialize(&dec_param);
if (dsErrorFree != ret)
Expand All @@ -35,6 +40,16 @@ H264Decoder::H264Decoder(std::uint32_t video_pixel_format)
decoder = nullptr;
assert(0);
}

video_input = fopen("video_input", "wb");
if(!video_input){
assert(0);
}

video_output = fopen("video_output", "wb");
if(!video_input){
assert(0);
}
}

H264Decoder::~H264Decoder()
Expand All @@ -44,6 +59,9 @@ H264Decoder::~H264Decoder()
decoder->Uninitialize();
decoder = nullptr;
}

fclose(video_input);
fclose(video_output);
}

/** Wrap underlying async APIs to expose sync API to decode input bitstream to
Expand All @@ -65,34 +83,69 @@ int H264Decoder::decode(const char *input_buffer,
unsigned char *dst[3];
SBufferInfo dst_info;

auto ret = decoder->DecodeFrameNoDelay(
auto ret = decoder->DecodeFrame2(
reinterpret_cast<const unsigned char *>(input_buffer),
input_length,
dst,
&dst_info);

if (dsErrorFree != ret)
{
std::cerr << " 1st decode frame failed" << std::endl;
std::cerr << " H264 decode frame failed" << std::endl;
// handle IDR request
} else {
std::cerr << "H264 Decode success " << std::endl;
}

if (dst_info.iBufferStatus == 1)
{
width = dst_info.UsrData.sSystemBuffer.iWidth;
height = dst_info.UsrData.sSystemBuffer.iHeight;

auto color_fmt = dst_info.UsrData.sSystemBuffer.iFormat;
#if 0
std::cerr << "Decoded Width : " << width << std::endl;
std::cerr << "Decoded height : " << height << std::endl;
std::cerr << "Decoded Format : " << color_fmt << std::endl;
std::cerr << "Decoded Stride 0 : " << dst_info.UsrData.sSystemBuffer.iStride[0] << std::endl;
std::cerr << "Decoded Stride 1 : " << dst_info.UsrData.sSystemBuffer.iStride[1] << std::endl;
#endif
auto y_size = width * height;
auto uv_size = y_size >> 2;

output_frame.resize(y_size + 2 * uv_size);
uint8_t *outp = output_frame.data();

size_t i = 0;
auto pPtr = dst[0];
for(i = 0; i < height; i++)
{
memcpy(outp, pPtr, width);
outp += width;
pPtr += dst_info.UsrData.sSystemBuffer.iStride[0];
}

pPtr = dst[1];
for(i = 0; i < height/2; i++)
{
memcpy(outp, pPtr, width/2);
outp += width/2;
pPtr += dst_info.UsrData.sSystemBuffer.iStride[1];
}

pPtr = dst[2];
for(i = 0; i < height/2; i++)
{
memcpy(outp, pPtr, width/2);
outp += width/2;
pPtr += dst_info.UsrData.sSystemBuffer.iStride[1];
}

std::cerr << "Decoder wrote " << output_frame.size() << std::endl;
}

width = dst_info.UsrData.sSystemBuffer.iWidth;
height = dst_info.UsrData.sSystemBuffer.iHeight;

const int y_size = width * height;
const int uv_size = y_size >> 2; // YUV420

output_frame.resize(y_size + 2 * uv_size);
uint8_t *outp = output_frame.data();

// Copy Y plane
memcpy(outp, dst[0], y_size);
memcpy(outp + y_size, dst[1], uv_size);
memcpy(outp + y_size + uv_size, dst[2], uv_size);

return 0;
}
106 changes: 61 additions & 45 deletions src/h264_encoder.cc
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@

#include <iostream>
#include <vector>
#include <cassert>

#include <string.h> // memcpy , strncat
#include <sstream>
#include <iomanip>

#include "h264_encoder.hh"

Expand All @@ -22,28 +23,13 @@ H264Encoder::H264Encoder(unsigned int video_max_width,
assert(0); // todo: throw exception?
}

// Apply client app settings
encodeParams.eSpsPpsIdStrategy = INCREASING_ID;
// encodeParams.bPrefixNalAddingCtrl = 1; // codec_type SVC
encodeParams.bPrefixNalAddingCtrl = 0; // codec_type AVC

encodeParams.iPicWidth = video_max_width;
encodeParams.iPicHeight = video_max_height;
encodeParams.fMaxFrameRate = video_max_frame_rate;
encodeParams.iTargetBitrate = video_max_bitrate; // bits/sec in base
encodeParams.bEnableFrameSkip = 1;

encodeParams.bEnableDenoise = false; // disable denoise
encodeParams.bEnableSceneChangeDetect = 1;
encodeParams.bEnableBackgroundDetection = 1;
encodeParams.bEnableAdaptiveQuant = 0;
encodeParams.bEnableLongTermReference = 1;
encodeParams.iLtrMarkPeriod = 30;
encodeParams.iNumRefFrame = AUTO_REF_PIC_COUNT;
encParamBase.fMaxFrameRate = 30;
encParamBase.iPicHeight = video_max_height;
encParamBase.iPicWidth = video_max_width;
encParamBase.iTargetBitrate = video_max_bitrate;
encParamBase.iRCMode = RC_OFF_MODE;
encoder->Initialize(&encParamBase);

encoder->InitializeExt(&encodeParams);

encoder->SetOption(ENCODER_OPTION_DATAFORMAT, &video_pixel_format);
}

H264Encoder::~H264Encoder()
Expand All @@ -55,6 +41,32 @@ H264Encoder::~H264Encoder()
}
}

static std::string to_hex(const std::vector<uint8_t> &data)
{
std::stringstream hex(std::ios_base::out);
hex.flags(std::ios::hex);
int i = 0;
for (const auto &byte : data)
{
hex << std::setw(2) << std::setfill('0') << int(byte);
i++;
if (i > 25)
break;
}
return hex.str();
}

static std::string to_hex(unsigned char* data, int stop)
{
std::stringstream hex(std::ios_base::out);
hex.flags(std::ios::hex);
for (int i = 0; i < stop; i++)
{
hex << std::setw(2) << std::setfill('0') << int(data[i]);
}
return hex.str();
}

int H264Encoder::encode(const char *input_buffer,
std::uint32_t input_length,
std::uint32_t width,
Expand Down Expand Up @@ -90,9 +102,16 @@ int H264Encoder::encode(const char *input_buffer,
sourcePicture.iStride[1] = (int) stride_uv;
sourcePicture.iStride[2] = (int) stride_uv;

//assert(0);
int videoFormat = videoFormatI420;
encoder->SetOption(ENCODER_OPTION_DATAFORMAT, &videoFormat);

if(genKeyFrame) {
auto ret = encoder->ForceIntraFrame(true);
std::cerr << "H264Enc: IDR Frame: " << ret << std::endl;
}

memset(&outputFrame, 0, sizeof (SFrameBSInfo));
int ret = encoder->EncodeFrame(&sourcePicture, &outputFrame);
if (ret == 0)
{
Expand All @@ -106,34 +125,31 @@ int H264Encoder::encode(const char *input_buffer,
}
}

// encode worked
auto a = outputFrame.iFrameSizeInBytes;
auto b = outputFrame.sLayerInfo->pNalLengthInByte;
output_bitstream.resize(outputFrame.iFrameSizeInBytes);
unsigned char *out_bits = output_bitstream.data();
memcpy(out_bits,
outputFrame.sLayerInfo->pBsBuf,
outputFrame.iFrameSizeInBytes);
for(int i = 0; i < outputFrame.iLayerNum; i++) {
auto len = 0;
// pNalLengthInByte[0]+pNalLengthInByte[1]+…+pNalLengthInByte[iNalCount-1].
for(int j =0; j < outputFrame.sLayerInfo[i].iNalCount; j++) {
len += outputFrame.sLayerInfo[i].pNalLengthInByte[j];
}

memcpy(out_bits,
outputFrame.sLayerInfo[i].pBsBuf,
len);

auto stop = len;
if(len > 25)
stop = 25;
std::cerr << to_hex(out_bits, stop) << std::endl;

out_bits += len;
}

total_bytes_encoded += output_bitstream.size();
total_frames_encoded++;

/*
// Debug log for frame number, type, avg time in usec, avg size in bytes
if (((total_frames_encoded-1) & 31) == 0) { // every 32 frames, ~1 sec
std::cerr << std::endl << height << "p "
<< (format ? "I420" : "NV12")
<< (encodeParams.request_key_frame ? " I " : " P ")
<< "Frame#" << (total_frames_encoded-1) << " "
<< bitstream.size() << " bytes "
<< encode_time << " usec, avg "
<< (total_bytes_encoded/total_frames_encoded) << " bytes "
<< (total_time_encoded/total_frames_encoded) << " usec" <<
std::endl;
//av1_encoder_stats_t stats = getStats(encoder);
//assert(0); // halt to check stats
}
*/

// success
return 0;
return outputFrame.eFrameType == videoFrameTypeIDR ? 1 : 0;
}

0 comments on commit 1eb170a

Please sign in to comment.