Added I420 (YUV 4:2:0) conversion option to avi recorder.
This commit is contained in:
parent
b9f6bf281f
commit
ce554b5e7b
|
@ -21,6 +21,7 @@ static int abufTail = 0;
|
||||||
static int abufSize = 0;
|
static int abufSize = 0;
|
||||||
static uint32_t *rawVideoBuf = NULL;
|
static uint32_t *rawVideoBuf = NULL;
|
||||||
static int16_t *rawAudioBuf = NULL;
|
static int16_t *rawAudioBuf = NULL;
|
||||||
|
static int videoFormat = 1;
|
||||||
//**************************************************************************************
|
//**************************************************************************************
|
||||||
|
|
||||||
static void convertRgb_32_to_24( const unsigned char *src, unsigned char *dest, int w, int h, int nPix )
|
static void convertRgb_32_to_24( const unsigned char *src, unsigned char *dest, int w, int h, int nPix )
|
||||||
|
@ -47,6 +48,104 @@ static void convertRgb_32_to_24( const unsigned char *src, unsigned char *dest,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//**************************************************************************************
|
//**************************************************************************************
|
||||||
|
/* For RGB2YUV: */
|
||||||
|
|
||||||
|
static const int RGB2YUV_SHIFT = 15; /* highest value where [RGB][YUV] fit in signed short */
|
||||||
|
|
||||||
|
static const int RY = 8414; // ((int)(( 65.738/256.0)*(1<<RGB2YUV_SHIFT)+0.5));
|
||||||
|
static const int RV = 14392; // ((int)((112.439/256.0)*(1<<RGB2YUV_SHIFT)+0.5));
|
||||||
|
static const int RU = -4856; // ((int)((-37.945/256.0)*(1<<RGB2YUV_SHIFT)+0.5));
|
||||||
|
|
||||||
|
static const int GY = 16519; // ((int)((129.057/256.0)*(1<<RGB2YUV_SHIFT)+0.5));
|
||||||
|
static const int GV = -12051;// ((int)((-94.154/256.0)*(1<<RGB2YUV_SHIFT)+0.5));
|
||||||
|
static const int GU = -9534; // ((int)((-74.494/256.0)*(1<<RGB2YUV_SHIFT)+0.5));
|
||||||
|
|
||||||
|
static const int BY = 3208; // ((int)(( 25.064/256.0)*(1<<RGB2YUV_SHIFT)+0.5));
|
||||||
|
static const int BV = -2339; // ((int)((-18.285/256.0)*(1<<RGB2YUV_SHIFT)+0.5));
|
||||||
|
static const int BU = 14392; // ((int)((112.439/256.0)*(1<<RGB2YUV_SHIFT)+0.5));
|
||||||
|
|
||||||
|
static const int Y_ADD = 16;
|
||||||
|
static const int U_ADD = 128;
|
||||||
|
static const int V_ADD = 128;
|
||||||
|
|
||||||
|
template<int PixStride>
|
||||||
|
void Convert_4byte_To_I420Frame(const void* data, unsigned char* dest, unsigned npixels, unsigned width)
|
||||||
|
{
|
||||||
|
const unsigned char* src = (const unsigned char*) data;
|
||||||
|
unsigned height = npixels / width;
|
||||||
|
|
||||||
|
unsigned pos = 0;
|
||||||
|
unsigned ypos = 0;
|
||||||
|
unsigned vpos = npixels;
|
||||||
|
unsigned upos = vpos + npixels / 4;
|
||||||
|
unsigned stride = width*PixStride;
|
||||||
|
|
||||||
|
/*fprintf(stderr, "npixels=%u, width=%u, height=%u, ypos=%u,upos=%u,vpos=%u",
|
||||||
|
npixels,width,height, ypos,upos,vpos);*/
|
||||||
|
|
||||||
|
/* This function is based on code from x264 svn version 711 */
|
||||||
|
/* TODO: Apply MMX optimization for 24-bit pixels */
|
||||||
|
|
||||||
|
for(unsigned y=0; y<height; y += 2)
|
||||||
|
{
|
||||||
|
for(unsigned x=0; x<width; x += 2)
|
||||||
|
{
|
||||||
|
//#ifdef __MMX__
|
||||||
|
// if(PixStride == 4)
|
||||||
|
// {
|
||||||
|
// c64_MMX p0_1; p0_1.Get(&src[pos]); // two 32-bit pixels (4*8)
|
||||||
|
// c64_MMX p2_3; p2_3.Get(&src[pos+stride]); // two 32-bit pixels
|
||||||
|
|
||||||
|
// pos += PixStride*2;
|
||||||
|
//
|
||||||
|
// Convert_I420_MMX_Common(p0_1, p2_3,
|
||||||
|
// dest+ypos,
|
||||||
|
// dest+ypos+width,
|
||||||
|
// dest+upos++,
|
||||||
|
// dest+vpos++);
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
//#endif
|
||||||
|
{
|
||||||
|
int c[3], rgb[3][4];
|
||||||
|
|
||||||
|
/* luma */
|
||||||
|
for(int n=0; n<3; ++n) c[n] = rgb[n][0] = src[pos + n];
|
||||||
|
for(int n=0; n<3; ++n) c[n] += rgb[n][1] = src[pos + n + stride];
|
||||||
|
pos += PixStride;
|
||||||
|
|
||||||
|
for(int n=0; n<3; ++n) c[n] += rgb[n][2] = src[pos + n];
|
||||||
|
for(int n=0; n<3; ++n) c[n] += rgb[n][3] = src[pos + n + stride];
|
||||||
|
pos += PixStride;
|
||||||
|
|
||||||
|
unsigned destpos[4] = { ypos, ypos+width, ypos+1, ypos+width+1 };
|
||||||
|
for(int n=0; n<4; ++n)
|
||||||
|
{
|
||||||
|
dest[destpos[n]]
|
||||||
|
= Y_ADD + ((RY * rgb[0][n]
|
||||||
|
+ GY * rgb[1][n]
|
||||||
|
+ BY * rgb[2][n]
|
||||||
|
) >> RGB2YUV_SHIFT); // y
|
||||||
|
}
|
||||||
|
|
||||||
|
dest[upos++] = (U_ADD + ((RU * c[0] + GU * c[1] + BU * c[2]) >> (RGB2YUV_SHIFT+2)) );
|
||||||
|
dest[vpos++] = (V_ADD + ((RV * c[0] + GV * c[1] + BV * c[2]) >> (RGB2YUV_SHIFT+2)) );
|
||||||
|
}
|
||||||
|
|
||||||
|
ypos += 2;
|
||||||
|
}
|
||||||
|
pos += stride;
|
||||||
|
ypos += width;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*fprintf(stderr, ",yr=%u,ur=%u,vr=%u\n",
|
||||||
|
ypos,upos,vpos);*/
|
||||||
|
|
||||||
|
//#ifdef __MMX__
|
||||||
|
// MMX_clear();
|
||||||
|
//#endif
|
||||||
|
}
|
||||||
|
//**************************************************************************************
|
||||||
int aviRecordOpenFile( const char *filepath, int format, int width, int height )
|
int aviRecordOpenFile( const char *filepath, int format, int width, int height )
|
||||||
{
|
{
|
||||||
char fourcc[8];
|
char fourcc[8];
|
||||||
|
@ -65,6 +164,11 @@ int aviRecordOpenFile( const char *filepath, int format, int width, int height )
|
||||||
|
|
||||||
memset( fourcc, 0, sizeof(fourcc) );
|
memset( fourcc, 0, sizeof(fourcc) );
|
||||||
|
|
||||||
|
if ( videoFormat )
|
||||||
|
{
|
||||||
|
strcpy( fourcc, "I420");
|
||||||
|
}
|
||||||
|
|
||||||
gwavi = new gwavi_t();
|
gwavi = new gwavi_t();
|
||||||
|
|
||||||
if ( gwavi->open( "/tmp/test.avi", nes_shm->video.ncol, nes_shm->video.nrow, fourcc, fps, &audioConfig ) )
|
if ( gwavi->open( "/tmp/test.avi", nes_shm->video.ncol, nes_shm->video.nrow, fourcc, fps, &audioConfig ) )
|
||||||
|
@ -227,9 +331,17 @@ void AviRecordDiskThread_t::run(void)
|
||||||
|
|
||||||
if ( numPixelsReady >= numPixels )
|
if ( numPixelsReady >= numPixels )
|
||||||
{
|
{
|
||||||
convertRgb_32_to_24( (const unsigned char*)videoOut, rgb24,
|
if ( videoFormat )
|
||||||
width, height, numPixels );
|
{
|
||||||
gwavi->add_frame( rgb24, numPixels*3 );
|
Convert_4byte_To_I420Frame<4>(videoOut,rgb24,numPixels,width);
|
||||||
|
gwavi->add_frame( rgb24, (numPixels*3)/2 );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
convertRgb_32_to_24( (const unsigned char*)videoOut, rgb24,
|
||||||
|
width, height, numPixels );
|
||||||
|
gwavi->add_frame( rgb24, numPixels*3 );
|
||||||
|
}
|
||||||
|
|
||||||
numPixelsReady = 0;
|
numPixelsReady = 0;
|
||||||
|
|
||||||
|
|
|
@ -79,6 +79,7 @@ gwavi_t::gwavi_t(void)
|
||||||
offsets_start = 0;
|
offsets_start = 0;
|
||||||
offsets = 0;
|
offsets = 0;
|
||||||
offset_count = 0;
|
offset_count = 0;
|
||||||
|
bits_per_pixel = 24;
|
||||||
}
|
}
|
||||||
|
|
||||||
gwavi_t::~gwavi_t(void)
|
gwavi_t::~gwavi_t(void)
|
||||||
|
@ -91,9 +92,16 @@ int
|
||||||
gwavi_t::open(const char *filename, unsigned int width, unsigned int height,
|
gwavi_t::open(const char *filename, unsigned int width, unsigned int height,
|
||||||
const char *fourcc, unsigned int fps, struct gwavi_audio_t *audio)
|
const char *fourcc, unsigned int fps, struct gwavi_audio_t *audio)
|
||||||
{
|
{
|
||||||
|
int size = 0;
|
||||||
|
memset( this->fourcc, 0, sizeof(this->fourcc) );
|
||||||
|
strcpy( this->fourcc, fourcc );
|
||||||
|
|
||||||
if (check_fourcc(fourcc) != 0)
|
if (check_fourcc(fourcc) != 0)
|
||||||
|
{
|
||||||
(void)fprintf(stderr, "WARNING: given fourcc does not seem to "
|
(void)fprintf(stderr, "WARNING: given fourcc does not seem to "
|
||||||
"be valid: %s\n", fourcc);
|
"be valid: %s\n", fourcc);
|
||||||
|
}
|
||||||
|
|
||||||
if (fps < 1)
|
if (fps < 1)
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -118,18 +126,34 @@ gwavi_t::open(const char *filename, unsigned int width, unsigned int height,
|
||||||
avi_header.data_streams = 1;
|
avi_header.data_streams = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( strcmp( fourcc, "I420" ) == 0 )
|
||||||
|
{ // I420 YUV 4:2:0
|
||||||
|
bits_per_pixel = 12;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ // Plain RGB24
|
||||||
|
bits_per_pixel = 24;
|
||||||
|
}
|
||||||
|
size = (width * height * bits_per_pixel);
|
||||||
|
|
||||||
|
if ( (size % 8) != 0 )
|
||||||
|
{
|
||||||
|
printf("Warning: Video Buffer Size not on an 8 bit boundary: %ix%i:%i\n", width, height, bits_per_pixel);
|
||||||
|
}
|
||||||
|
size = size / 8;
|
||||||
|
|
||||||
/* this field gets updated when calling gwavi_close() */
|
/* this field gets updated when calling gwavi_close() */
|
||||||
avi_header.number_of_frames = 0;
|
avi_header.number_of_frames = 0;
|
||||||
avi_header.width = width;
|
avi_header.width = width;
|
||||||
avi_header.height = height;
|
avi_header.height = height;
|
||||||
avi_header.buffer_size = (width * height * 3);
|
avi_header.buffer_size = size;
|
||||||
|
|
||||||
/* set stream header */
|
/* set stream header */
|
||||||
(void)strcpy(stream_header_v.data_type, "vids");
|
(void)strcpy(stream_header_v.data_type, "vids");
|
||||||
(void)memcpy(stream_header_v.codec, fourcc, 4);
|
(void)memcpy(stream_header_v.codec, fourcc, 4);
|
||||||
stream_header_v.time_scale = 1;
|
stream_header_v.time_scale = 1;
|
||||||
stream_header_v.data_rate = fps;
|
stream_header_v.data_rate = fps;
|
||||||
stream_header_v.buffer_size = (width * height * 3);
|
stream_header_v.buffer_size = size;
|
||||||
stream_header_v.data_length = 0;
|
stream_header_v.data_length = 0;
|
||||||
|
|
||||||
/* set stream format */
|
/* set stream format */
|
||||||
|
@ -137,13 +161,13 @@ gwavi_t::open(const char *filename, unsigned int width, unsigned int height,
|
||||||
stream_format_v.width = width;
|
stream_format_v.width = width;
|
||||||
stream_format_v.height = height;
|
stream_format_v.height = height;
|
||||||
stream_format_v.num_planes = 1;
|
stream_format_v.num_planes = 1;
|
||||||
stream_format_v.bits_per_pixel = 24;
|
stream_format_v.bits_per_pixel = bits_per_pixel;
|
||||||
stream_format_v.compression_type =
|
stream_format_v.compression_type =
|
||||||
((unsigned int)fourcc[3] << 24) +
|
((unsigned int)fourcc[3] << 24) +
|
||||||
((unsigned int)fourcc[2] << 16) +
|
((unsigned int)fourcc[2] << 16) +
|
||||||
((unsigned int)fourcc[1] << 8) +
|
((unsigned int)fourcc[1] << 8) +
|
||||||
((unsigned int)fourcc[0]);
|
((unsigned int)fourcc[0]);
|
||||||
stream_format_v.image_size = width * height * 3;
|
stream_format_v.image_size = size;
|
||||||
stream_format_v.colors_used = 0;
|
stream_format_v.colors_used = 0;
|
||||||
stream_format_v.colors_important = 0;
|
stream_format_v.colors_important = 0;
|
||||||
|
|
||||||
|
@ -467,8 +491,12 @@ int
|
||||||
gwavi_t::set_codec( const char *fourcc)
|
gwavi_t::set_codec( const char *fourcc)
|
||||||
{
|
{
|
||||||
if (check_fourcc(fourcc) != 0)
|
if (check_fourcc(fourcc) != 0)
|
||||||
|
{
|
||||||
(void)fprintf(stderr, "WARNING: given fourcc does not seem to "
|
(void)fprintf(stderr, "WARNING: given fourcc does not seem to "
|
||||||
"be valid: %s\n", fourcc);
|
"be valid: %s\n", fourcc);
|
||||||
|
}
|
||||||
|
memset( this->fourcc, 0, sizeof(this->fourcc) );
|
||||||
|
strcpy( this->fourcc, fourcc );
|
||||||
|
|
||||||
memcpy(stream_header_v.codec, fourcc, 4);
|
memcpy(stream_header_v.codec, fourcc, 4);
|
||||||
stream_format_v.compression_type =
|
stream_format_v.compression_type =
|
||||||
|
@ -495,7 +523,7 @@ gwavi_t::set_codec( const char *fourcc)
|
||||||
int
|
int
|
||||||
gwavi_t::set_size( unsigned int width, unsigned int height)
|
gwavi_t::set_size( unsigned int width, unsigned int height)
|
||||||
{
|
{
|
||||||
unsigned int size = (width * height * 3);
|
unsigned int size = (width * height * bits_per_pixel) / 8;
|
||||||
|
|
||||||
avi_header.data_rate = size;
|
avi_header.data_rate = size;
|
||||||
avi_header.width = width;
|
avi_header.width = width;
|
||||||
|
|
|
@ -146,6 +146,8 @@ class gwavi_t
|
||||||
long offsets_start;
|
long offsets_start;
|
||||||
unsigned int *offsets;
|
unsigned int *offsets;
|
||||||
int offset_count;
|
int offset_count;
|
||||||
|
int bits_per_pixel;
|
||||||
|
char fourcc[8];
|
||||||
|
|
||||||
// helper functions
|
// helper functions
|
||||||
int write_avi_header(FILE *out, struct gwavi_header_t *avi_header);
|
int write_avi_header(FILE *out, struct gwavi_header_t *avi_header);
|
||||||
|
|
Loading…
Reference in New Issue