-aviio: Added functionality to read RGB24 and YUV420p uncompressed video frames. [Ryan Holtz]

This commit is contained in:
mooglyguy 2019-07-21 09:15:31 +02:00
parent da6da2eeb4
commit 7dc59ce975
2 changed files with 137 additions and 15 deletions

View File

@ -365,6 +365,10 @@ public:
// HuffYUV helpers
avi_file::error huffyuv_decompress_to_yuy16(const std::uint8_t *data, std::uint32_t numbytes, bitmap_yuy16 &bitmap) const;
// Uncompressed helpers
avi_file::error uncompressed_rgb24_to_rgb32(const std::uint8_t *data, std::uint32_t numbytes, bitmap_rgb32 &bitmap) const;
avi_file::error uncompressed_yuv420p_to_rgb32(const std::uint8_t *data, std::uint32_t numbytes, bitmap_rgb32 &bitmap) const;
private:
struct huffyuv_table
{
@ -456,6 +460,7 @@ public:
virtual movie_info const &get_movie_info() const override;
virtual std::uint32_t first_sample_in_frame(std::uint32_t framenum) const override;
virtual error read_uncompressed_video_frame(std::uint32_t framenum, bitmap_rgb32 &bitmap) override;
virtual error read_video_frame(std::uint32_t framenum, bitmap_yuy16 &bitmap) override;
virtual error read_sound_samples(int channel, std::uint32_t firstsample, std::uint32_t numsamples, std::int16_t *output) override;
@ -1483,6 +1488,73 @@ avi_file::error avi_stream::huffyuv_decompress_to_yuy16(const std::uint8_t *data
}
/*-------------------------------------------------
uncompressed_rgb24_to_rgb32 - convert a raw
RGB24-encoded frame to an RGB32 bitmap
-------------------------------------------------*/
avi_file::error avi_stream::uncompressed_rgb24_to_rgb32(const std::uint8_t *data, std::uint32_t numbytes, bitmap_rgb32 &bitmap) const
{
std::uint32_t dataoffs = 0;
/* uncompressed video */
for (int y = 0; y < m_height; y++)
{
std::uint32_t *dest = &bitmap.pix32(y);
/* loop over pixels */
for (int x = 0; x < m_width; x++)
{
const uint8_t b = data[dataoffs++];
const uint8_t g = data[dataoffs++];
const uint8_t r = data[dataoffs++];
*dest++ = 0xff << 24 | r << 16 | g << 8 | b;
}
}
return avi_file::error::NONE;
}
/*-------------------------------------------------
uncompressed_yuv420p_to_rgb32 - convert a
YUV420p-encoded frame to an RGB32 bitmap
-------------------------------------------------*/
avi_file::error avi_stream::uncompressed_yuv420p_to_rgb32(const std::uint8_t *data, std::uint32_t numbytes, bitmap_rgb32 &bitmap) const
{
const int width = bitmap.width();
const int height = bitmap.height();
const int size_total = width * height;
/* uncompressed video */
for (int y = 0; y < m_height; y++)
{
std::uint32_t *dest = &bitmap.pix32(y);
/* loop over pixels */
for (int x = 0; x < m_width; x++)
{
const uint8_t luma = data[y * width + x];
const uint8_t u = data[(y / 2) * (width / 2) + x / 2 + size_total];
const uint8_t v = data[(y / 2) * (width / 2) + x / 2 + size_total + size_total / 4];
int r = luma + (1.370705f * (v - 0x80));
int g = luma - (0.698001f * (v - 0x80)) - (0.337633f * (u - 0x80));
int b = luma + (1.732446f * (u - 0x80));
r = (r < 0) ? 0 : ((r > 255) ? 255 : r);
g = (g < 0) ? 0 : ((g > 255) ? 255 : g);
b = (b < 0) ? 0 : ((b > 255) ? 255 : b);
*dest++ = 0xff << 24 | r << 16 | g << 8 | b;
}
}
return avi_file::error::NONE;
}
/*-------------------------------------------------
avi_close - close an AVI movie file
-------------------------------------------------*/
@ -1602,22 +1674,67 @@ std::uint32_t avi_file_impl::first_sample_in_frame(std::uint32_t framenum) const
/*-------------------------------------------------
avi_read_video_frame - read video data
for a particular frame from the AVI file,
converting to YUY16 format
read_uncompressed_video_frame - read raw video
data for a particular frame from the AVI file,
converting to RGB32 format
-------------------------------------------------*/
/**
* @fn avi_error avi_read_video_frame(avi_file *file, std::uint32_t framenum, bitmap_yuy16 &bitmap)
*
* @brief Avi read video frame.
*
* @param [in,out] file If non-null, the file.
* @param framenum The framenum.
* @param [in,out] bitmap The bitmap.
*
* @return An avi_error.
*/
avi_file::error avi_file_impl::read_uncompressed_video_frame(std::uint32_t framenum, bitmap_rgb32 &bitmap)
{
/* get the video stream */
avi_stream *const stream = get_video_stream();
if (!stream)
return error::INVALID_STREAM;
if (stream->format() != FORMAT_UNCOMPRESSED && stream->format() != FORMAT_DIB && stream->format() != FORMAT_RGB && stream->format() != FORMAT_RAW && stream->format() != FORMAT_I420)
return error::UNSUPPORTED_VIDEO_FORMAT;
if (bitmap.width() < stream->width() || bitmap.height() < stream->height())
bitmap.resize(stream->width(), stream->height());
/* assume one chunk == one frame */
if (framenum >= stream->chunks())
return error::INVALID_FRAME;
/* we only support YUY-style bitmaps (16bpp) */
if (bitmap.width() < stream->width() || bitmap.height() < stream->height())
return error::INVALID_BITMAP;
/* expand the tempbuffer to hold the data if necessary */
error avierr = error::NONE;
avierr = expand_tempbuffer(stream->chunk(framenum).length);
if (avierr != error::NONE)
return avierr;
/* read in the data */
std::uint32_t bytes_read;
osd_file::error const filerr = m_file->read(&m_tempbuffer[0], stream->chunk(framenum).offset, stream->chunk(framenum).length, bytes_read);
if (filerr != osd_file::error::NONE || bytes_read != stream->chunk(framenum).length)
return error::READ_ERROR;
/* validate this is good data */
std::uint32_t const chunkid = fetch_32bits(&m_tempbuffer[0]);
if (chunkid == get_chunkid_for_stream(stream))
{
/* uncompressed YUV420p */
if (stream->format() == FORMAT_I420)
avierr = stream->uncompressed_yuv420p_to_rgb32(&m_tempbuffer[8], stream->chunk(framenum).length - 8, bitmap);
else
avierr = stream->uncompressed_rgb24_to_rgb32(&m_tempbuffer[8], stream->chunk(framenum).length - 8, bitmap);
}
else
{
avierr = error::INVALID_DATA;
}
return avierr;
}
/*-------------------------------------------------
read_video_frame - read video data for a
particular frame from the AVI file, converting
to YUY16 format
-------------------------------------------------*/
avi_file::error avi_file_impl::read_video_frame(std::uint32_t framenum, bitmap_yuy16 &bitmap)
{

View File

@ -29,7 +29,11 @@
#define FORMAT_VYUY AVI_FOURCC('V','Y','U','Y')
#define FORMAT_YUY2 AVI_FOURCC('Y','U','Y','2')
#define FORMAT_HFYU AVI_FOURCC('H','F','Y','U')
#define FORMAT_I420 AVI_FOURCC('I','4','2','0')
#define FORMAT_DIB AVI_FOURCC('D','I','B',' ')
#define FORMAT_RGB AVI_FOURCC('R','G','B',' ')
#define FORMAT_RAW AVI_FOURCC('R','A','W',' ')
#define FORMAT_UNCOMPRESSED 0x00000000
class avi_file
@ -115,6 +119,7 @@ public:
virtual movie_info const &get_movie_info() const = 0;
virtual std::uint32_t first_sample_in_frame(std::uint32_t framenum) const = 0;
virtual error read_uncompressed_video_frame(std::uint32_t framenum, bitmap_rgb32 &bitmap) = 0;
virtual error read_video_frame(std::uint32_t framenum, bitmap_yuy16 &bitmap) = 0;
virtual error read_sound_samples(int channel, std::uint32_t firstsample, std::uint32_t numsamples, std::int16_t *output) = 0;