Initial community commit
This commit is contained in:
parent
537bcbc862
commit
fc06254474
16440 changed files with 4239995 additions and 2 deletions
212
Src/h264/h264_mp4_decoder.cpp
Normal file
212
Src/h264/h264_mp4_decoder.cpp
Normal file
|
@ -0,0 +1,212 @@
|
|||
#include "h264_mp4_decoder.h"
|
||||
#include "../winamp/wa_ipc.h"
|
||||
#include <Mferror.h>
|
||||
uint32_t Read24(const uint8_t *data)
|
||||
{
|
||||
// ugh, 24bit size
|
||||
uint32_t this_size=0;
|
||||
uint8_t *this_size_p = (uint8_t *)&this_size;
|
||||
this_size_p[0] = data[2];
|
||||
this_size_p[1] = data[1];
|
||||
this_size_p[2] = data[0];
|
||||
return this_size;
|
||||
}
|
||||
|
||||
uint32_t GetNALUSize(uint64_t nalu_size_bytes, const uint8_t *h264_data, size_t data_len)
|
||||
{
|
||||
if ((data_len) < (nalu_size_bytes))
|
||||
return 0;
|
||||
|
||||
switch(nalu_size_bytes)
|
||||
{
|
||||
case 1:
|
||||
return *h264_data;
|
||||
case 2:
|
||||
{
|
||||
return (h264_data[0] << 8) | h264_data[1];
|
||||
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
return Read24(h264_data);
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
uint32_t this_size = *(uint32_t *)h264_data;
|
||||
this_size = htonl(this_size);
|
||||
return this_size;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
H264MP4Decoder::H264MP4Decoder()
|
||||
{
|
||||
nalu_size_bytes=0;
|
||||
width=0;
|
||||
height=0;
|
||||
}
|
||||
|
||||
H264MP4Decoder::~H264MP4Decoder()
|
||||
{
|
||||
for (size_t i=0;i<buffered_frames.size();i++) {
|
||||
nullsoft_h264_frame_data frame_data = buffered_frames[i];
|
||||
decoder.FreeFrame((YV12_PLANES *)frame_data.data, frame_data.decoder_data);
|
||||
}
|
||||
}
|
||||
|
||||
int H264MP4Decoder::Open(MP4FileHandle mp4_file, MP4TrackId mp4_track)
|
||||
{
|
||||
this->mp4_file=mp4_file;
|
||||
this->mp4_track=mp4_track;
|
||||
decoder.Open();
|
||||
// TODO error checking
|
||||
uint8_t **seqHeaders = 0, **pictHeaders = 0;
|
||||
uint32_t *seqHeadersSize = 0, *pictHeadersSize = 0;
|
||||
|
||||
__try
|
||||
{
|
||||
MP4GetTrackH264SeqPictHeaders(mp4_file, mp4_track,
|
||||
&seqHeaders, &seqHeadersSize,
|
||||
&pictHeaders, &pictHeadersSize);
|
||||
|
||||
if (seqHeadersSize)
|
||||
{
|
||||
for (uint32_t i = 0; seqHeadersSize[i] != 0; i++)
|
||||
{
|
||||
decoder.Feed(seqHeaders[i], seqHeadersSize[i], 0);
|
||||
MP4Free(seqHeaders[i]);
|
||||
}
|
||||
}
|
||||
MP4Free(seqHeadersSize);
|
||||
|
||||
if (pictHeadersSize)
|
||||
{
|
||||
for (uint32_t i = 0; pictHeadersSize[i] != 0; i++)
|
||||
{
|
||||
decoder.Feed(pictHeaders[i], pictHeadersSize[i], 0);
|
||||
MP4Free(pictHeaders[i]);
|
||||
}
|
||||
}
|
||||
MP4Free(pictHeadersSize);
|
||||
|
||||
MP4GetTrackH264LengthSize(mp4_file, mp4_track, &nalu_size_bytes);
|
||||
}
|
||||
__except(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
return MP4_VIDEO_FAILURE;
|
||||
}
|
||||
|
||||
return MP4_VIDEO_SUCCESS;
|
||||
}
|
||||
|
||||
int H264MP4Decoder::GetOutputFormat(int *x, int *y, int *color_format, double *aspect_ratio)
|
||||
{
|
||||
bool flip;
|
||||
|
||||
if (SUCCEEDED(decoder.GetOutputFormat(&width, &height, &flip, aspect_ratio))) {
|
||||
*x = width;
|
||||
*y = height;
|
||||
*color_format = htonl('YV12');
|
||||
return MP4_VIDEO_SUCCESS;
|
||||
}
|
||||
return MP4_VIDEO_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
int H264MP4Decoder::DecodeSample(const void *inputBuffer, size_t inputBufferBytes, MP4Timestamp timestamp)
|
||||
{
|
||||
const uint8_t *h264_data = (const uint8_t *)inputBuffer;
|
||||
while (inputBufferBytes)
|
||||
{
|
||||
uint32_t this_size =GetNALUSize(nalu_size_bytes, h264_data, inputBufferBytes);
|
||||
if (this_size == 0)
|
||||
return MP4_VIDEO_FAILURE;
|
||||
|
||||
inputBufferBytes-=nalu_size_bytes;
|
||||
h264_data+=nalu_size_bytes;
|
||||
if (this_size > inputBufferBytes)
|
||||
return MP4_VIDEO_FAILURE;
|
||||
|
||||
for (;;) {
|
||||
uint64_t hundrednanos = MP4ConvertFromTrackTimestamp(mp4_file, mp4_track, timestamp, MP4_NANOSECONDS_TIME_SCALE/100ULL);
|
||||
HRESULT hr = decoder.Feed(h264_data, this_size, hundrednanos);
|
||||
if (hr == MF_E_NOTACCEPTING) {
|
||||
nullsoft_h264_frame_data frame_data;
|
||||
if (FAILED(decoder.GetFrame((YV12_PLANES **)&frame_data.data, &frame_data.decoder_data, &frame_data.local_timestamp))) {
|
||||
continue;
|
||||
}
|
||||
buffered_frames.push_back(frame_data);
|
||||
} else if (FAILED(hr)) {
|
||||
return MP4_VIDEO_FAILURE;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
inputBufferBytes-=this_size;
|
||||
h264_data+=this_size;
|
||||
}
|
||||
return MP4_VIDEO_SUCCESS;
|
||||
}
|
||||
|
||||
int H264MP4Decoder::CanHandleCodec(const char *codecName)
|
||||
{
|
||||
return !strcmp(codecName, "avc1");
|
||||
}
|
||||
|
||||
void H264MP4Decoder::Flush()
|
||||
{
|
||||
for (size_t i=0;i<buffered_frames.size();i++) {
|
||||
nullsoft_h264_frame_data frame_data = buffered_frames[i];
|
||||
decoder.FreeFrame((YV12_PLANES *)frame_data.data, frame_data.decoder_data);
|
||||
}
|
||||
decoder.Flush();
|
||||
}
|
||||
|
||||
int H264MP4Decoder::GetPicture(void **data, void **decoder_data, MP4Timestamp *timestamp)
|
||||
{
|
||||
if (!buffered_frames.empty()) {
|
||||
nullsoft_h264_frame_data frame_data = buffered_frames[0];
|
||||
buffered_frames.erase(buffered_frames.begin());
|
||||
*data = frame_data.data;
|
||||
*decoder_data = frame_data.decoder_data;
|
||||
*timestamp = MP4ConvertToTrackTimestamp(mp4_file, mp4_track, frame_data.local_timestamp, MP4_NANOSECONDS_TIME_SCALE/100ULL);
|
||||
return MP4_VIDEO_SUCCESS;
|
||||
}
|
||||
|
||||
uint64_t local_timestamp;
|
||||
if (SUCCEEDED(decoder.GetFrame((YV12_PLANES **)data, decoder_data, &local_timestamp))) {
|
||||
*timestamp = MP4ConvertToTrackTimestamp(mp4_file, mp4_track, local_timestamp, MP4_NANOSECONDS_TIME_SCALE/100ULL);
|
||||
return MP4_VIDEO_SUCCESS;
|
||||
} else {
|
||||
return MP4_VIDEO_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
void H264MP4Decoder::FreePicture(void *data, void *decoder_data)
|
||||
{
|
||||
decoder.FreeFrame((YV12_PLANES *)data, decoder_data);
|
||||
}
|
||||
|
||||
void H264MP4Decoder::HurryUp(int state)
|
||||
{
|
||||
// TODO if (decoder)
|
||||
//H264_HurryUp(decoder, state);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define CBCLASS H264MP4Decoder
|
||||
START_DISPATCH;
|
||||
CB(MPEG4_VIDEO_OPEN, Open)
|
||||
CB(MPEG4_VIDEO_GETOUTPUTFORMAT, GetOutputFormat)
|
||||
CB(MPEG4_VIDEO_DECODE, DecodeSample)
|
||||
CB(MPEG4_VIDEO_HANDLES_CODEC, CanHandleCodec)
|
||||
VCB(MPEG4_VIDEO_FLUSH, Flush)
|
||||
CB(MPEG4_VIDEO_GET_PICTURE, GetPicture)
|
||||
VCB(MPEG4_VIDEO_FREE_PICTURE, FreePicture)
|
||||
VCB(MPEG4_VIDEO_HURRY_UP, HurryUp)
|
||||
END_DISPATCH;
|
||||
#undef CBCLASS
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue