summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/util/aviio.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/util/aviio.cpp')
-rw-r--r--src/lib/util/aviio.cpp3369
1 files changed, 1629 insertions, 1740 deletions
diff --git a/src/lib/util/aviio.cpp b/src/lib/util/aviio.cpp
index a448128070b..339a4de3231 100644
--- a/src/lib/util/aviio.cpp
+++ b/src/lib/util/aviio.cpp
@@ -1,5 +1,5 @@
// license:BSD-3-Clause
-// copyright-holders:Aaron Giles
+// copyright-holders:Aaron Giles, Vas Crabb
/***************************************************************************
aviio.c
@@ -8,8 +8,10 @@
***************************************************************************/
-#include <stdlib.h>
-#include <assert.h>
+#include <array>
+#include <cassert>
+#include <cstdlib>
+#include <cstring>
#include "aviio.h"
@@ -45,7 +47,7 @@
* @brief A macro that defines four gigabytes.
*/
-#define FOUR_GB ((UINT64)1 << 32)
+#define FOUR_GB (std::uint64_t(1) << 32)
/**
* @def MAX_SOUND_CHANNELS
@@ -222,7 +224,7 @@
#define HUFFYUV_PREDICT_DECORR 0x40
-
+namespace {
/***************************************************************************
TYPE DEFINITIONS
***************************************************************************/
@@ -235,14 +237,12 @@
struct avi_chunk
{
- /** @brief The offset. */
- UINT64 offset; /* file offset of chunk header */
- /** @brief The size. */
- UINT64 size; /* size of this chunk */
- /** @brief The type. */
- UINT32 type; /* type of this chunk */
- /** @brief The listtype. */
- UINT32 listtype; /* type of this list (if we are a list) */
+ avi_chunk() : offset(0), size(0), type(0), listtype(0) { }
+
+ std::uint64_t offset; /* file offset of chunk header */
+ std::uint64_t size; /* size of this chunk */
+ std::uint32_t type; /* type of this chunk */
+ std::uint32_t listtype; /* type of this list (if we are a list) */
};
/**
@@ -253,211 +253,297 @@ struct avi_chunk
struct avi_chunk_list
{
- /** @brief The offset. */
- UINT64 offset; /* offset in the file of header */
- /** @brief The length. */
- UINT32 length; /* length of the chunk including header */
+ std::uint64_t offset; /* offset in the file of header */
+ std::uint32_t length; /* length of the chunk including header */
};
/**
- * @struct huffyuv_table
+ * @struct avi_stream
*
- * @brief A huffyuv table.
+ * @brief An avi stream.
*/
-struct huffyuv_table
-{
- /** @brief The shift[ 256]. */
- UINT8 shift[256]; /* bit shift amounts */
- /** @brief The bits[ 256]. */
- UINT32 bits[256]; /* bit match values */
- /** @brief The mask[ 256]. */
- UINT32 mask[256]; /* bit mask values */
- /** @brief The baselookup[ 65536]. */
- UINT16 baselookup[65536]; /* base lookup table */
- /** @brief The extralookup. */
- UINT16 * extralookup; /* extra lookup tables */
-};
+class avi_stream
+{
+public:
+ avi_stream()
+ : m_type(0)
+ , m_format(0)
+ , m_rate(0)
+ , m_scale(0)
+ , m_samples(0)
+ , m_chunks()
+ , m_width(0)
+ , m_height(0)
+ , m_depth(0)
+ , m_interlace(0)
+ , m_huffyuv()
+ , m_channels(0)
+ , m_samplebits(0)
+ , m_samplerate(0)
+ , m_saved_strh_offset(0)
+ , m_saved_indx_offset(0)
+ {
+ }
-/**
- * @struct huffyuv_data
- *
- * @brief A huffyuv data.
- */
+ void initialize_video(avi_file::movie_info const &info)
+ {
+ m_type = STREAMTYPE_VIDS;
+ m_format = info.video_format;
+ m_rate = info.video_timescale;
+ m_scale = info.video_sampletime;
+ m_width = info.video_width;
+ m_height = info.video_height;
+ m_depth = info.video_depth;
+ }
-struct huffyuv_data
-{
- /** @brief The predictor. */
- UINT8 predictor; /* predictor */
- /** @brief The table[ 3]. */
- huffyuv_table table[3]; /* array of tables */
-};
+ void initialize_audio(avi_file::movie_info const &info)
+ {
+ m_type = STREAMTYPE_AUDS;
+ m_format = info.audio_format;
+ m_rate = info.audio_timescale;
+ m_scale = info.audio_sampletime;
+ m_channels = info.audio_channels;
+ m_samplebits = info.audio_samplebits;
+ m_samplerate = info.audio_samplerate;
+ }
-/**
- * @struct avi_stream
- *
- * @brief An avi stream.
- */
+ std::uint32_t type() const { return m_type; }
+ std::uint32_t format() const { return m_format; }
+
+ std::uint32_t rate() const { return m_rate; }
+ std::uint32_t scale() const { return m_scale; }
+ std::uint32_t samples() const { return m_samples; }
+ void set_samples(std::uint32_t value) { m_samples = value; }
+ std::uint32_t add_samples(std::uint32_t value) { return m_samples += value; }
+
+ std::uint32_t chunks() const { return m_chunks.size(); }
+ avi_chunk_list const &chunk(std::uint32_t index) const { assert(index < m_chunks.size()); return m_chunks[index]; }
+ avi_chunk_list &chunk(std::uint32_t index) { assert(index < m_chunks.size()); return m_chunks[index]; }
+ avi_file::error set_chunk_info(std::uint32_t index, std::uint64_t offset, std::uint32_t length);
+ void set_chunks(std::uint32_t count) { assert(count <= m_chunks.size()); m_chunks.resize(count); }
+
+ std::uint32_t width() const { return m_width; }
+ std::uint32_t height() const { return m_height; }
+ std::uint32_t depth() const { return m_depth; }
+
+ std::uint16_t channels() const { return m_channels; }
+ std::uint16_t samplebits() const { return m_samplebits; }
+ std::uint32_t samplerate() const { return m_samplerate; }
+ std::uint32_t bytes_per_sample() const { return (m_samplebits / 8) * m_channels; }
+
+ avi_file::error set_strh_data(std::uint8_t const *data, std::uint32_t size);
+ avi_file::error set_strf_data(std::uint8_t const *data, std::uint32_t size);
+
+ std::uint64_t &saved_strh_offset() { return m_saved_strh_offset; }
+ std::uint64_t &saved_indx_offset() { return m_saved_indx_offset; }
+
+ // RGB helpers
+ avi_file::error rgb32_compress_to_rgb(const bitmap_rgb32 &bitmap, std::uint8_t *data, std::uint32_t numbytes) const;
+
+ // YUY helpers
+ avi_file::error yuv_decompress_to_yuy16(const std::uint8_t *data, std::uint32_t numbytes, bitmap_yuy16 &bitmap) const;
+ avi_file::error yuy16_compress_to_yuy(const bitmap_yuy16 &bitmap, std::uint8_t *data, std::uint32_t numbytes) const;
+
+ // HuffYUV helpers
+ avi_file::error huffyuv_decompress_to_yuy16(const std::uint8_t *data, std::uint32_t numbytes, bitmap_yuy16 &bitmap) const;
+
+private:
+ struct huffyuv_table
+ {
+ std::uint8_t shift[256]; /* bit shift amounts */
+ std::uint32_t bits[256]; /* bit match values */
+ std::uint32_t mask[256]; /* bit mask values */
+ std::uint16_t baselookup[65536]; /* base lookup table */
+ std::vector<std::uint16_t> extralookup; /* extra lookup tables */
+ };
+
+ struct huffyuv_data
+ {
+ std::uint8_t predictor; /* predictor */
+ huffyuv_table table[3]; /* array of tables */
+ };
-struct avi_stream
-{
- /** @brief The type. */
- UINT32 type; /* subtype of stream */
- /** @brief Describes the format to use. */
- UINT32 format; /* format of stream data */
-
- /** @brief The rate. */
- UINT32 rate; /* timescale for stream */
- /** @brief The scale. */
- UINT32 scale; /* duration of one sample in the stream */
- /** @brief The samples. */
- UINT32 samples; /* number of samples */
-
- /** @brief The chunk. */
- avi_chunk_list * chunk; /* list of chunks */
- /** @brief The chunks. */
- UINT32 chunks; /* chunks currently known */
- /** @brief The chunksalloc. */
- UINT32 chunksalloc; /* number of chunks allocated */
-
- /** @brief The width. */
- UINT32 width; /* width of video */
- /** @brief The height. */
- UINT32 height; /* height of video */
- /** @brief The depth. */
- UINT32 depth; /* depth of video */
- /** @brief The interlace. */
- UINT8 interlace; /* interlace parameters */
- /** @brief The huffyuv. */
- huffyuv_data * huffyuv; /* huffyuv decompression data */
-
- /** @brief The channels. */
- UINT16 channels; /* audio channels */
- /** @brief The samplebits. */
- UINT16 samplebits; /* audio bits per sample */
- /** @brief The samplerate. */
- UINT32 samplerate; /* audio sample rate */
+ avi_file::error huffyuv_extract_tables(const std::uint8_t *chunkdata, std::uint32_t size);
+
+ std::uint32_t m_type; /* subtype of stream */
+ std::uint32_t m_format; /* format of stream data */
+
+ std::uint32_t m_rate; /* timescale for stream */
+ std::uint32_t m_scale; /* duration of one sample in the stream */
+ std::uint32_t m_samples; /* number of samples */
+
+ std::vector<avi_chunk_list> m_chunks; /* list of chunks */
+
+ std::uint32_t m_width; /* width of video */
+ std::uint32_t m_height; /* height of video */
+ std::uint32_t m_depth; /* depth of video */
+ std::uint8_t m_interlace; /* interlace parameters */
+ std::unique_ptr<huffyuv_data const> m_huffyuv; /* huffyuv decompression data */
+
+ std::uint16_t m_channels; /* audio channels */
+ std::uint16_t m_samplebits; /* audio bits per sample */
+ std::uint32_t m_samplerate; /* audio sample rate */
/* only used when creating */
- /** @brief The saved strh offset. */
- UINT64 saved_strh_offset; /* writeoffset of strh chunk */
- /** @brief The saved indx offset. */
- UINT64 saved_indx_offset; /* writeoffset of indx chunk */
+ std::uint64_t m_saved_strh_offset; /* writeoffset of strh chunk */
+ std::uint64_t m_saved_indx_offset; /* writeoffset of indx chunk */
};
/**
- * @struct avi_file
+ * @class avi_file_impl
*
* @brief An avi file.
*/
-struct avi_file
+class avi_file_impl : public avi_file
{
- /* shared data */
- /** @brief The file. */
- osd_file * file; /* pointer to open file */
- /** @brief The type. */
- int type; /* type of access (read/create) */
- /** @brief The information. */
- avi_movie_info info; /* movie info structure */
- /** @brief The tempbuffer. */
- UINT8 * tempbuffer; /* temporary buffer */
- /** @brief The tempbuffersize. */
- UINT32 tempbuffersize; /* size of the temporary buffer */
-
- /* only used when reading */
- /** @brief The streams. */
- int streams; /* number of streams */
- /** @brief The stream. */
- avi_stream * stream; /* allocated array of stream information */
- /** @brief The rootchunk. */
- avi_chunk rootchunk; /* dummy root chunk that wraps the whole file */
-
- /* only used when creating */
- /** @brief The writeoffs. */
- UINT64 writeoffs; /* current file write offset */
- /** @brief The riffbase. */
- UINT64 riffbase; /* base of the current RIFF */
-
- /** @brief The chunkstack[ 8]. */
- avi_chunk chunkstack[8]; /* stack of chunks we are writing */
- /** @brief The chunksp. */
- int chunksp; /* stack pointer for the current chunk */
-
- /** @brief The saved movi offset. */
- UINT64 saved_movi_offset; /* writeoffset of movi list */
- /** @brief The saved avih offset. */
- UINT64 saved_avih_offset; /* writeoffset of avih chunk */
-
- /** @brief The soundbuf. */
- INT16 * soundbuf; /* buffer for sound data */
- /** @brief The soundbuf samples. */
- UINT32 soundbuf_samples; /* length of sound buffer in samples */
- /** @brief The soundbuf chansamples[ maximum sound channels]. */
- UINT32 soundbuf_chansamples[MAX_SOUND_CHANNELS]; /* samples in buffer for each channel */
- /** @brief The soundbuf chunks. */
- UINT32 soundbuf_chunks; /* number of chunks completed so far */
- /** @brief The soundbuf frames. */
- UINT32 soundbuf_frames; /* number of frames ahead of the video */
-};
-
+public:
+ avi_file_impl(osd_file::ptr &&file, std::uint64_t length) : avi_file_impl()
+ {
+ m_file = std::move(file);
+ m_type = FILETYPE_READ;
+
+ // make a root atom
+ m_rootchunk.offset = 0;
+ m_rootchunk.size = length;
+ m_rootchunk.type = 0;
+ m_rootchunk.listtype = 0;
+ }
+ avi_file_impl(osd_file::ptr &&file, movie_info const &info) : avi_file_impl()
+ {
+ m_file = std::move(file);
+ m_type = FILETYPE_CREATE;
-/***************************************************************************
- PROTOTYPES
-***************************************************************************/
+ // copy the movie info
+ m_info = info;
+ m_info.video_numsamples = 0;
+ m_info.audio_numsamples = 0;
-/* stream helpers */
+ // initialize the video track
+ m_streams.emplace_back();
+ m_streams.back().initialize_video(m_info);
-/* core chunk read routines */
-static avi_error get_first_chunk(avi_file *file, const avi_chunk *parent, avi_chunk *newchunk);
-static avi_error get_next_chunk(avi_file *file, const avi_chunk *parent, avi_chunk *newchunk);
-static avi_error find_first_chunk(avi_file *file, UINT32 findme, const avi_chunk *container, avi_chunk *result);
-static avi_error find_next_chunk(avi_file *file, UINT32 findme, const avi_chunk *container, avi_chunk *result);
-static avi_error get_next_chunk_internal(avi_file *file, const avi_chunk *parent, avi_chunk *newchunk, UINT64 offset);
-static avi_error read_chunk_data(avi_file *file, const avi_chunk *chunk, UINT8 **buffer);
+ // initialize the audio track
+ if (m_info.audio_channels > 0)
+ {
+ m_streams.emplace_back();
+ m_streams.back().initialize_audio(m_info);
+ }
+ }
-/* chunk read helpers */
-static avi_error read_movie_data(avi_file *file);
-static avi_error extract_movie_info(avi_file *file);
-static avi_error parse_avih_chunk(avi_file *file, avi_chunk *avih);
-static avi_error parse_strh_chunk(avi_file *file, avi_stream *stream, avi_chunk *strh);
-static avi_error parse_strf_chunk(avi_file *file, avi_stream *stream, avi_chunk *strf);
-static avi_error parse_indx_chunk(avi_file *file, avi_stream *stream, avi_chunk *strf);
-static avi_error parse_idx1_chunk(avi_file *file, UINT64 baseoffset, avi_chunk *idx1);
+ virtual ~avi_file_impl() override;
+
+ virtual void printf_chunks() override;
+
+ 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_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;
+
+ virtual error append_video_frame(bitmap_yuy16 &bitmap) override;
+ virtual error append_video_frame(bitmap_rgb32 &bitmap) override;
+ virtual error append_sound_samples(int channel, std::int16_t const *samples, std::uint32_t numsamples, std::uint32_t sampleskip) override;
+
+ error read_movie_data();
+ error write_initial_headers();
+ error soundbuf_initialize();
+
+private:
+ avi_file_impl()
+ : m_file()
+ , m_type(0)
+ , m_info({ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 })
+ , m_tempbuffer()
+ , m_streams()
+ , m_rootchunk()
+ , m_writeoffs(0)
+ , m_riffbase(0)
+ , m_chunkstack()
+ , m_chunksp(0)
+ , m_saved_movi_offset(0)
+ , m_saved_avih_offset(0)
+ , m_soundbuf()
+ , m_soundbuf_samples(0)
+ , m_soundbuf_chunks(0)
+ , m_soundbuf_frames(0)
+ {
+ std::fill(std::begin(m_soundbuf_chansamples), std::end(m_soundbuf_chansamples), 0);
+ }
-/* core chunk write routines */
-static avi_error chunk_open(avi_file *file, UINT32 type, UINT32 listtype, UINT32 estlength);
-static avi_error chunk_close(avi_file *file);
-static avi_error chunk_write(avi_file *file, UINT32 type, const void *data, UINT32 length);
-static avi_error chunk_overwrite(avi_file *file, UINT32 type, const void *data, UINT32 length, UINT64 *offset, int initial_write);
+ avi_stream *get_video_stream();
+ avi_stream *get_audio_stream(int channel, int &offset);
+ std::uint32_t compute_idx1_size() const;
+ std::uint32_t get_chunkid_for_stream(const avi_stream *stream) const;
+ std::uint32_t framenum_to_samplenum(std::uint32_t framenum) const;
+ error expand_tempbuffer(std::uint32_t length);
+
+ // core chunk read routines
+ error get_first_chunk(avi_chunk const *parent, avi_chunk &newchunk);
+ error get_next_chunk(avi_chunk const *parent, avi_chunk &newchunk);
+ error find_first_chunk(std::uint32_t findme, avi_chunk const *container, avi_chunk &result);
+ error find_next_chunk(std::uint32_t findme, avi_chunk const *container, avi_chunk &result);
+ error find_first_list(std::uint32_t findme, avi_chunk const *container, avi_chunk &result);
+ error find_next_list(std::uint32_t findme, avi_chunk const *container, avi_chunk &result);
+ error get_next_chunk_internal(avi_chunk const *parent, avi_chunk &newchunk, std::uint64_t offset);
+ error read_chunk_data(avi_chunk const &chunk, std::unique_ptr<std::uint8_t []> &buffer);
+
+ // chunk read helpers
+ error extract_movie_info();
+ error parse_avih_chunk(avi_chunk const &avih);
+ error parse_strh_chunk(avi_stream &stream, avi_chunk const &strh);
+ error parse_strf_chunk(avi_stream &stream, avi_chunk const &strf);
+ error parse_indx_chunk(avi_stream &stream, avi_chunk const &strf);
+ error parse_idx1_chunk(std::uint64_t baseoffset, avi_chunk const &idx1);
+
+ // core chunk write routines
+ error chunk_open(std::uint32_t type, std::uint32_t listtype, std::uint32_t estlength);
+ error chunk_close();
+ error chunk_write(std::uint32_t type, const void *data, std::uint32_t length);
+ error chunk_overwrite(std::uint32_t type, const void *data, std::uint32_t length, std::uint64_t &offset, bool initial_write);
+
+ // chunk write helpers
+ error write_avih_chunk(bool initial_write);
+ error write_strh_chunk(avi_stream &stream, bool initial_write);
+ error write_strf_chunk(avi_stream const &stream);
+ error write_indx_chunk(avi_stream &stream, bool initial_write);
+ error write_idx1_chunk();
+
+ // sound buffering helpers
+ error soundbuf_write_chunk(std::uint32_t framenum);
+ error soundbuf_flush(bool only_flush_full);
+
+ // debugging
+ void printf_chunk_recursive(avi_chunk const *chunk, int indent);
-/* chunk write helpers */
-static avi_error write_initial_headers(avi_file *file);
-static avi_error write_avih_chunk(avi_file *file, int initial_write);
-static avi_error write_strh_chunk(avi_file *file, avi_stream *stream, int initial_write);
-static avi_error write_strf_chunk(avi_file *file, avi_stream *stream);
-static avi_error write_indx_chunk(avi_file *file, avi_stream *stream, int initial_write);
-static avi_error write_idx1_chunk(avi_file *file);
+ /* shared data */
+ osd_file::ptr m_file; /* pointer to open file */
+ int m_type; /* type of access (read/create) */
+ movie_info m_info; /* movie info structure */
+ std::vector<std::uint8_t> m_tempbuffer; /* temporary buffer */
-/* sound buffering helpers */
-static avi_error soundbuf_initialize(avi_file *file);
-static avi_error soundbuf_write_chunk(avi_file *file, UINT32 framenum);
-static avi_error soundbuf_flush(avi_file *file, int only_flush_full);
+ /* only used when reading */
+ std::vector<avi_stream> m_streams; /* allocated array of stream information */
+ avi_chunk m_rootchunk; /* dummy root chunk that wraps the whole file */
-/* RGB helpers */
-static avi_error rgb32_compress_to_rgb(avi_stream *stream, const bitmap_rgb32 &bitmap, UINT8 *data, UINT32 numbytes);
+ /* only used when creating */
+ std::uint64_t m_writeoffs; /* current file write offset */
+ std::uint64_t m_riffbase; /* base of the current RIFF */
-/* YUY helpers */
-static avi_error yuv_decompress_to_yuy16(avi_stream *stream, const UINT8 *data, UINT32 numbytes, bitmap_yuy16 &bitmap);
-static avi_error yuy16_compress_to_yuy(avi_stream *stream, const bitmap_yuy16 &bitmap, UINT8 *data, UINT32 numbytes);
+ std::array<avi_chunk, 8> m_chunkstack; /* stack of chunks we are writing */
+ int m_chunksp; /* stack pointer for the current chunk */
-/* HuffYUV helpers */
-static avi_error huffyuv_extract_tables(avi_stream *stream, const UINT8 *chunkdata, UINT32 size);
-static avi_error huffyuv_decompress_to_yuy16(avi_stream *stream, const UINT8 *data, UINT32 numbytes, bitmap_yuy16 &bitmap);
+ std::uint64_t m_saved_movi_offset; /* writeoffset of movi list */
+ std::uint64_t m_saved_avih_offset; /* writeoffset of avih chunk */
-/* debugging */
-static void printf_chunk_recursive(avi_file *file, avi_chunk *chunk, int indent);
+ std::vector<std::int16_t> m_soundbuf; /* buffer for sound data */
+ std::uint32_t m_soundbuf_samples; /* length of sound buffer in samples */
+ std::uint32_t m_soundbuf_chansamples[MAX_SOUND_CHANNELS]; /* samples in buffer for each channel */
+ std::uint32_t m_soundbuf_chunks; /* number of chunks completed so far */
+ std::uint32_t m_soundbuf_frames; /* number of frames ahead of the video */
+};
@@ -471,7 +557,7 @@ static void printf_chunk_recursive(avi_file *file, avi_chunk *chunk, int indent)
-------------------------------------------------*/
/**
- * @fn static inline UINT16 fetch_16bits(const UINT8 *data)
+ * @fn static inline std::uint16_t fetch_16bits(const std::uint8_t *data)
*
* @brief Fetches the 16bits.
*
@@ -480,7 +566,7 @@ static void printf_chunk_recursive(avi_file *file, avi_chunk *chunk, int indent)
* @return The 16bits.
*/
-static inline UINT16 fetch_16bits(const UINT8 *data)
+inline std::uint16_t fetch_16bits(const std::uint8_t *data)
{
return data[0] | (data[1] << 8);
}
@@ -492,7 +578,7 @@ static inline UINT16 fetch_16bits(const UINT8 *data)
-------------------------------------------------*/
/**
- * @fn static inline UINT32 fetch_32bits(const UINT8 *data)
+ * @fn static inline std::uint32_t fetch_32bits(const std::uint8_t *data)
*
* @brief Fetches the 32bits.
*
@@ -501,7 +587,7 @@ static inline UINT16 fetch_16bits(const UINT8 *data)
* @return The 32bits.
*/
-static inline UINT32 fetch_32bits(const UINT8 *data)
+inline std::uint32_t fetch_32bits(const std::uint8_t *data)
{
return data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
}
@@ -513,7 +599,7 @@ static inline UINT32 fetch_32bits(const UINT8 *data)
-------------------------------------------------*/
/**
- * @fn static inline UINT64 fetch_64bits(const UINT8 *data)
+ * @fn static inline std::uint64_t fetch_64bits(const std::uint8_t *data)
*
* @brief Fetches the 64bits.
*
@@ -522,12 +608,12 @@ static inline UINT32 fetch_32bits(const UINT8 *data)
* @return The 64bits.
*/
-static inline UINT64 fetch_64bits(const UINT8 *data)
+inline std::uint64_t fetch_64bits(const std::uint8_t *data)
{
- return (UINT64)data[0] | ((UINT64)data[1] << 8) |
- ((UINT64)data[2] << 16) | ((UINT64)data[3] << 24) |
- ((UINT64)data[4] << 32) | ((UINT64)data[5] << 40) |
- ((UINT64)data[6] << 48) | ((UINT64)data[7] << 56);
+ return std::uint64_t(data[0]) | (std::uint64_t(data[1]) << 8) |
+ (std::uint64_t(data[2]) << 16) | (std::uint64_t(data[3]) << 24) |
+ (std::uint64_t(data[4]) << 32) | (std::uint64_t(data[5]) << 40) |
+ (std::uint64_t(data[6]) << 48) | (std::uint64_t(data[7]) << 56);
}
@@ -537,7 +623,7 @@ static inline UINT64 fetch_64bits(const UINT8 *data)
-------------------------------------------------*/
/**
- * @fn static inline void put_16bits(UINT8 *data, UINT16 value)
+ * @fn static inline void put_16bits(std::uint8_t *data, std::uint16_t value)
*
* @brief Puts the 16bits.
*
@@ -545,7 +631,7 @@ static inline UINT64 fetch_64bits(const UINT8 *data)
* @param value The value.
*/
-static inline void put_16bits(UINT8 *data, UINT16 value)
+inline void put_16bits(std::uint8_t *data, std::uint16_t value)
{
data[0] = value >> 0;
data[1] = value >> 8;
@@ -558,7 +644,7 @@ static inline void put_16bits(UINT8 *data, UINT16 value)
-------------------------------------------------*/
/**
- * @fn static inline void put_32bits(UINT8 *data, UINT32 value)
+ * @fn static inline void put_32bits(std::uint8_t *data, std::uint32_t value)
*
* @brief Puts the 32bits.
*
@@ -566,7 +652,7 @@ static inline void put_16bits(UINT8 *data, UINT16 value)
* @param value The value.
*/
-static inline void put_32bits(UINT8 *data, UINT32 value)
+inline void put_32bits(std::uint8_t *data, std::uint32_t value)
{
data[0] = value >> 0;
data[1] = value >> 8;
@@ -581,7 +667,7 @@ static inline void put_32bits(UINT8 *data, UINT32 value)
-------------------------------------------------*/
/**
- * @fn static inline void put_64bits(UINT8 *data, UINT64 value)
+ * @fn static inline void put_64bits(std::uint8_t *data, std::uint64_t value)
*
* @brief Puts the 64bits.
*
@@ -589,7 +675,7 @@ static inline void put_32bits(UINT8 *data, UINT32 value)
* @param value The value.
*/
-static inline void put_64bits(UINT8 *data, UINT64 value)
+inline void put_64bits(std::uint8_t *data, std::uint64_t value)
{
data[0] = value >> 0;
data[1] = value >> 8;
@@ -602,29 +688,120 @@ static inline void put_64bits(UINT8 *data, UINT64 value)
}
+/**
+ * @fn static void u64toa(std::uint64_t val, char *output)
+ *
+ * @brief 64toas.
+ *
+ * @param val The value.
+ * @param [in,out] output If non-null, the output.
+ */
+
+inline void u64toa(std::uint64_t val, char *output)
+{
+ std::uint32_t lo = std::uint32_t(val & 0xffffffff);
+ std::uint32_t hi = std::uint32_t(val >> 32);
+ if (hi != 0)
+ sprintf(output, "%X%08X", hi, lo);
+ else
+ sprintf(output, "%X", lo);
+}
+
+
+/*-------------------------------------------------
+ set_stream_chunk_info - set the chunk info
+ for a given chunk within a stream
+-------------------------------------------------*/
+
+/**
+ * @fn static inline avi_error set_stream_chunk_info(avi_stream *stream, std::uint32_t index, std::uint64_t offset, std::uint32_t length)
+ *
+ * @brief Sets stream chunk information.
+ *
+ * @param [in,out] stream If non-null, the stream.
+ * @param index Zero-based index of the.
+ * @param offset The offset.
+ * @param length The length.
+ *
+ * @return An avi_error.
+ */
+
+inline avi_file::error avi_stream::set_chunk_info(std::uint32_t index, std::uint64_t offset, std::uint32_t length)
+{
+ /* if we need to allocate more, allocate more */
+ if (index >= m_chunks.capacity())
+ {
+ try { m_chunks.reserve((std::max<std::size_t>)(index, m_chunks.capacity() + 1000)); }
+ catch (...) { return avi_file::error::NO_MEMORY; }
+ }
+
+ /* update the number of chunks */
+ m_chunks.resize((std::max<std::size_t>)(m_chunks.size(), index + 1));
+
+ /* set the data */
+ m_chunks[index].offset = offset;
+ m_chunks[index].length = length;
+
+ return avi_file::error::NONE;
+}
+
+
+inline avi_file::error avi_stream::set_strh_data(std::uint8_t const *data, std::uint32_t size)
+{
+ m_type = fetch_32bits(&data[0]);
+ m_scale = fetch_32bits(&data[20]);
+ m_rate = fetch_32bits(&data[24]);
+ m_samples = fetch_32bits(&data[32]);
+ return avi_file::error::NONE;
+}
+
+
+inline avi_file::error avi_stream::set_strf_data(std::uint8_t const *data, std::uint32_t size)
+{
+ /* audio and video streams have differing headers */
+ if (m_type == STREAMTYPE_VIDS)
+ {
+ m_width = fetch_32bits(&data[4]);
+ m_height = fetch_32bits(&data[8]);
+ m_depth = fetch_16bits(&data[14]);
+ m_format = fetch_32bits(&data[16]);
+
+ /* extra extraction for HuffYUV data */
+ if ((m_format == FORMAT_HFYU) && (size >= 56))
+ {
+ avi_file::error const avierr = huffyuv_extract_tables(data, size);
+ if (avierr != avi_file::error::NONE)
+ return avierr;
+ }
+ }
+ else if (m_type == STREAMTYPE_AUDS)
+ {
+ m_channels = fetch_16bits(&data[2]);
+ m_samplebits = fetch_16bits(&data[14]);
+ m_samplerate = fetch_32bits(&data[4]);
+ }
+ return avi_file::error::NONE;
+}
+
+
/*-------------------------------------------------
get_video_stream - return a pointer to the
video stream
-------------------------------------------------*/
/**
- * @fn static inline avi_stream *get_video_stream(avi_file *file)
+ * @fn static inline avi_stream *get_video_stream()
*
* @brief Gets video stream.
*
- * @param [in,out] file If non-null, the file.
- *
* @return null if it fails, else the video stream.
*/
-static inline avi_stream *get_video_stream(avi_file *file)
+inline avi_stream *avi_file_impl::get_video_stream()
{
- int streamnum;
-
- /* find the video stream */
- for (streamnum = 0; streamnum < file->streams; streamnum++)
- if (file->stream[streamnum].type == STREAMTYPE_VIDS)
- return &file->stream[streamnum];
+ for (int streamnum = 0; streamnum < m_streams.size(); streamnum++)
+ if (m_streams[streamnum].type() == STREAMTYPE_VIDS)
+ return &m_streams[streamnum];
return nullptr;
}
@@ -647,21 +824,18 @@ static inline avi_stream *get_video_stream(avi_file *file)
* @return null if it fails, else the audio stream.
*/
-static inline avi_stream *get_audio_stream(avi_file *file, int channel, int *offset)
+inline avi_stream *avi_file_impl::get_audio_stream(int channel, int &offset)
{
- int streamnum;
-
/* find the audios stream */
- for (streamnum = 0; streamnum < file->streams; streamnum++)
- if (file->stream[streamnum].type == STREAMTYPE_AUDS)
+ for (int streamnum = 0; streamnum < m_streams.size(); streamnum++)
+ if (m_streams[streamnum].type() == STREAMTYPE_AUDS)
{
- if (channel < file->stream[streamnum].channels)
+ if (channel < m_streams[streamnum].channels())
{
- if (offset != nullptr)
- *offset = channel;
- return &file->stream[streamnum];
+ offset = channel;
+ return &m_streams[streamnum];
}
- channel -= file->stream[streamnum].channels;
+ channel -= m_streams[streamnum].channels();
}
return nullptr;
@@ -669,58 +843,12 @@ static inline avi_stream *get_audio_stream(avi_file *file, int channel, int *off
/*-------------------------------------------------
- set_stream_chunk_info - set the chunk info
- for a given chunk within a stream
--------------------------------------------------*/
-
-/**
- * @fn static inline avi_error set_stream_chunk_info(avi_stream *stream, UINT32 index, UINT64 offset, UINT32 length)
- *
- * @brief Sets stream chunk information.
- *
- * @param [in,out] stream If non-null, the stream.
- * @param index Zero-based index of the.
- * @param offset The offset.
- * @param length The length.
- *
- * @return An avi_error.
- */
-
-static inline avi_error set_stream_chunk_info(avi_stream *stream, UINT32 index, UINT64 offset, UINT32 length)
-{
- /* if we need to allocate more, allocate more */
- if (index >= stream->chunksalloc)
- {
- UINT32 newcount = MAX(index, stream->chunksalloc + 1000);
- avi_chunk_list *newchunks = (avi_chunk_list *)malloc(newcount * sizeof(stream->chunk[0]));
- if (newchunks == nullptr)
- return AVIERR_NO_MEMORY;
- if (stream->chunk != nullptr)
- {
- memcpy(newchunks, stream->chunk, stream->chunksalloc * sizeof(stream->chunk[0]));
- free(stream->chunk);
- }
- stream->chunk = newchunks;
- stream->chunksalloc = newcount;
- }
-
- /* set the data */
- stream->chunk[index].offset = offset;
- stream->chunk[index].length = length;
-
- /* update the number of chunks */
- stream->chunks = MAX(stream->chunks, index + 1);
- return AVIERR_NONE;
-}
-
-
-/*-------------------------------------------------
compute_idx1_size - compute the size of the
idx1 chunk
-------------------------------------------------*/
/**
- * @fn static inline UINT32 compute_idx1_size(avi_file *file)
+ * @fn static inline std::uint32_t compute_idx1_size(avi_file *file)
*
* @brief Calculates the index 1 size.
*
@@ -729,14 +857,13 @@ static inline avi_error set_stream_chunk_info(avi_stream *stream, UINT32 index,
* @return The calculated index 1 size.
*/
-static inline UINT32 compute_idx1_size(avi_file *file)
+inline std::uint32_t avi_file_impl::compute_idx1_size() const
{
int chunks = 0;
- int strnum;
/* count chunks in streams */
- for (strnum = 0; strnum < file->streams; strnum++)
- chunks += file->stream[strnum].chunks;
+ for (int strnum = 0; strnum < m_streams.size(); strnum++)
+ chunks += m_streams[strnum].chunks();
return chunks * 16 + 8;
}
@@ -748,7 +875,7 @@ static inline UINT32 compute_idx1_size(avi_file *file)
-------------------------------------------------*/
/**
- * @fn static inline UINT32 get_chunkid_for_stream(avi_file *file, avi_stream *stream)
+ * @fn static inline std::uint32_t get_chunkid_for_stream(avi_file *file, avi_stream *stream)
*
* @brief Gets chunkid for stream.
*
@@ -758,14 +885,14 @@ static inline UINT32 compute_idx1_size(avi_file *file)
* @return The chunkid for stream.
*/
-static inline UINT32 get_chunkid_for_stream(avi_file *file, avi_stream *stream)
+inline std::uint32_t avi_file_impl::get_chunkid_for_stream(const avi_stream *stream) const
{
- UINT32 chunkid;
+ std::uint32_t chunkid;
- chunkid = AVI_FOURCC('0' + (stream - file->stream) / 10, '0' + (stream - file->stream) % 10, 0, 0);
- if (stream->type == STREAMTYPE_VIDS)
- chunkid |= (stream->format == 0) ? CHUNKTYPE_XXDB : CHUNKTYPE_XXDC;
- else if (stream->type == STREAMTYPE_AUDS)
+ chunkid = AVI_FOURCC('0' + (stream - &m_streams[0]) / 10, '0' + (stream - &m_streams[0]) % 10, 0, 0);
+ if (stream->type() == STREAMTYPE_VIDS)
+ chunkid |= (stream->format() == 0) ? CHUNKTYPE_XXDB : CHUNKTYPE_XXDC;
+ else if (stream->type() == STREAMTYPE_AUDS)
chunkid |= CHUNKTYPE_XXWB;
return chunkid;
@@ -778,19 +905,19 @@ static inline UINT32 get_chunkid_for_stream(avi_file *file, avi_stream *stream)
-------------------------------------------------*/
/**
- * @fn static inline UINT32 framenum_to_samplenum(avi_file *file, UINT32 framenum)
+ * @fn static inline std::uint32_t framenum_to_samplenum(avi_file *file, std::uint32_t framenum)
*
* @brief Framenum to samplenum.
*
* @param [in,out] file If non-null, the file.
* @param framenum The framenum.
*
- * @return An UINT32.
+ * @return An std::uint32_t.
*/
-static inline UINT32 framenum_to_samplenum(avi_file *file, UINT32 framenum)
+inline std::uint32_t avi_file_impl::framenum_to_samplenum(std::uint32_t framenum) const
{
- return ((UINT64)file->info.audio_samplerate * (UINT64)framenum * (UINT64)file->info.video_sampletime + file->info.video_timescale - 1) / (UINT64)file->info.video_timescale;
+ return (std::uint64_t(m_info.audio_samplerate) * std::uint64_t(framenum) * std::uint64_t(m_info.video_sampletime) + m_info.video_timescale - 1) / std::uint64_t(m_info.video_timescale);
}
@@ -801,7 +928,7 @@ static inline UINT32 framenum_to_samplenum(avi_file *file, UINT32 framenum)
-------------------------------------------------*/
/**
- * @fn static inline avi_error expand_tempbuffer(avi_file *file, UINT32 length)
+ * @fn static inline avi_error expand_tempbuffer(avi_file *file, std::uint32_t length)
*
* @brief Expand tempbuffer.
*
@@ -811,207 +938,532 @@ static inline UINT32 framenum_to_samplenum(avi_file *file, UINT32 framenum)
* @return An avi_error.
*/
-static inline avi_error expand_tempbuffer(avi_file *file, UINT32 length)
+inline avi_file::error avi_file_impl::expand_tempbuffer(std::uint32_t length)
{
/* expand the tempbuffer to hold the data if necessary */
- if (length > file->tempbuffersize)
+ if (length > m_tempbuffer.size())
{
- file->tempbuffersize = 2 * length;
- UINT8 *newbuffer = (UINT8 *)malloc(file->tempbuffersize);
- if (newbuffer == nullptr)
- return AVIERR_NO_MEMORY;
- if (file->tempbuffer != nullptr)
- free(file->tempbuffer);
- file->tempbuffer = newbuffer;
+ try { m_tempbuffer.resize(2 * length); }
+ catch (...) { return error::NO_MEMORY; }
}
- return AVIERR_NONE;
+ return error::NONE;
}
+/*-------------------------------------------------
+ rgb32_compress_to_rgb - "compress" an RGB32
+ bitmap to an RGB encoded frame
+-------------------------------------------------*/
+
+/**
+ * @fn static avi_error rgb32_compress_to_rgb(avi_stream *stream, const bitmap_rgb32 &bitmap, std::uint8_t *data, std::uint32_t numbytes)
+ *
+ * @brief RGB 32 compress to RGB.
+ *
+ * @param [in,out] stream If non-null, the stream.
+ * @param bitmap The bitmap.
+ * @param [in,out] data If non-null, the data.
+ * @param numbytes The numbytes.
+ *
+ * @return An avi_error.
+ */
+
+avi_file::error avi_stream::rgb32_compress_to_rgb(const bitmap_rgb32 &bitmap, std::uint8_t *data, std::uint32_t numbytes) const
+{
+ int const height = (std::min<int>)(m_height, bitmap.height());
+ int const width = (std::min<int>)(m_width, bitmap.width());
+ std::uint8_t *const dataend = data + numbytes;
+ int x, y;
+
+ /* compressed video */
+ for (y = 0; y < height; y++)
+ {
+ const std::uint32_t *source = &bitmap.pix32(y);
+ std::uint8_t *dest = data + (m_height - 1 - y) * m_width * 3;
+
+ for (x = 0; x < width && dest < dataend; x++)
+ {
+ rgb_t pix = *source++;
+ *dest++ = pix.b();
+ *dest++ = pix.g();
+ *dest++ = pix.r();
+ }
+
+ /* fill in any blank space on the right */
+ for ( ; x < m_width && dest < dataend; x++)
+ {
+ *dest++ = 0;
+ *dest++ = 0;
+ *dest++ = 0;
+ }
+ }
+
+ /* fill in any blank space on the bottom */
+ for ( ; y < m_height; y++)
+ {
+ std::uint8_t *dest = data + (m_height - 1 - y) * m_width * 3;
+ for (x = 0; x < m_width && dest < dataend; x++)
+ {
+ *dest++ = 0;
+ *dest++ = 0;
+ *dest++ = 0;
+ }
+ }
+
+ return avi_file::error::NONE;
+}
-/***************************************************************************
- IMPLEMENTATION
-***************************************************************************/
/*-------------------------------------------------
- avi_open - open an AVI movie file for read
+ yuv_decompress_to_yuy16 - decompress a YUV
+ encoded frame to a YUY16 bitmap
-------------------------------------------------*/
/**
- * @fn avi_error avi_open(const char *filename, avi_file **file)
+ * @fn static avi_error yuv_decompress_to_yuy16(avi_stream *stream, const std::uint8_t *data, std::uint32_t numbytes, bitmap_yuy16 &bitmap)
*
- * @brief Queries if a given avi open.
+ * @brief Yuv decompress to yuy 16.
*
- * @param filename Filename of the file.
- * @param [in,out] file If non-null, the file.
+ * @param [in,out] stream If non-null, the stream.
+ * @param data The data.
+ * @param numbytes The numbytes.
+ * @param [in,out] bitmap The bitmap.
*
* @return An avi_error.
*/
-avi_error avi_open(const char *filename, avi_file **file)
+avi_file::error avi_stream::yuv_decompress_to_yuy16(const std::uint8_t *data, std::uint32_t numbytes, bitmap_yuy16 &bitmap) const
{
- avi_file *newfile = nullptr;
- file_error filerr;
- avi_error avierr;
- UINT64 length;
-
- /* allocate the file */
- newfile = (avi_file *)malloc(sizeof(*newfile));
- if (newfile == nullptr)
- return AVIERR_NO_MEMORY;
- memset(newfile, 0, sizeof(*newfile));
- newfile->type = FILETYPE_READ;
+ std::uint16_t const *const dataend = reinterpret_cast<const std::uint16_t *>(data + numbytes);
+ int x, y;
- /* open the file */
- filerr = osd_open(filename, OPEN_FLAG_READ, &newfile->file, &length);
- if (filerr != FILERR_NONE)
+ /* compressed video */
+ for (y = 0; y < m_height; y++)
{
- avierr = AVIERR_CANT_OPEN_FILE;
- goto error;
+ const std::uint16_t *source = reinterpret_cast<const std::uint16_t *>(data) + y * m_width;
+ std::uint16_t *dest = &bitmap.pix16(y);
+
+ /* switch off the compression */
+ switch (m_format)
+ {
+ case FORMAT_UYVY:
+ for (x = 0; x < m_width && source < dataend; x++)
+ *dest++ = *source++;
+ break;
+
+ case FORMAT_VYUY:
+ case FORMAT_YUY2:
+ for (x = 0; x < m_width && source < dataend; x++)
+ {
+ std::uint16_t pix = *source++;
+ *dest++ = (pix >> 8) | (pix << 8);
+ }
+ break;
+ }
}
- /* make a root atom */
- newfile->rootchunk.offset = 0;
- newfile->rootchunk.size = length;
- newfile->rootchunk.type = 0;
- newfile->rootchunk.listtype = 0;
+ return avi_file::error::NONE;
+}
- /* parse the data */
- avierr = read_movie_data(newfile);
- if (avierr != AVIERR_NONE)
- goto error;
- *file = newfile;
- return AVIERR_NONE;
+/*-------------------------------------------------
+ yuy16_compress_to_yuy - "compress" a YUY16
+ bitmap to a YUV encoded frame
+-------------------------------------------------*/
-error:
- /* clean up after an error */
- if (newfile != nullptr)
+/**
+ * @fn static avi_error yuy16_compress_to_yuy(avi_stream *stream, const bitmap_yuy16 &bitmap, std::uint8_t *data, std::uint32_t numbytes)
+ *
+ * @brief Yuy 16 compress to yuy.
+ *
+ * @param [in,out] stream If non-null, the stream.
+ * @param bitmap The bitmap.
+ * @param [in,out] data If non-null, the data.
+ * @param numbytes The numbytes.
+ *
+ * @return An avi_error.
+ */
+
+avi_file::error avi_stream::yuy16_compress_to_yuy(const bitmap_yuy16 &bitmap, std::uint8_t *data, std::uint32_t numbytes) const
+{
+ std::uint16_t *const dataend = reinterpret_cast<std::uint16_t *>(data + numbytes);
+ int x, y;
+
+ /* compressed video */
+ for (y = 0; y < m_height; y++)
{
- if (newfile->file != nullptr)
- osd_close(newfile->file);
- free(newfile);
+ const std::uint16_t *source = &bitmap.pix16(y);
+ std::uint16_t *dest = reinterpret_cast<std::uint16_t *>(data) + y * m_width;
+
+ /* switch off the compression */
+ switch (m_format)
+ {
+ case FORMAT_UYVY:
+ for (x = 0; x < m_width && dest < dataend; x++)
+ *dest++ = *source++;
+ break;
+
+ case FORMAT_VYUY:
+ case FORMAT_YUY2:
+ for (x = 0; x < m_width && dest < dataend; x++)
+ {
+ std::uint16_t pix = *source++;
+ *dest++ = (pix >> 8) | (pix << 8);
+ }
+ break;
+ }
}
- return avierr;
+
+ return avi_file::error::NONE;
}
/*-------------------------------------------------
- avi_create - create a new AVI movie file
+ huffyuv_extract_tables - extract HuffYUV
+ tables
-------------------------------------------------*/
/**
- * @fn avi_error avi_create(const char *filename, const avi_movie_info *info, avi_file **file)
+ * @fn static avi_error huffyuv_extract_tables(avi_stream *stream, const std::uint8_t *chunkdata, std::uint32_t size)
*
- * @brief Avi create.
+ * @brief Huffyuv extract tables.
*
- * @param filename Filename of the file.
- * @param info The information.
- * @param [in,out] file If non-null, the file.
+ * @param [in,out] stream If non-null, the stream.
+ * @param chunkdata The chunkdata.
+ * @param size The size.
*
* @return An avi_error.
*/
-avi_error avi_create(const char *filename, const avi_movie_info *info, avi_file **file)
+avi_file::error avi_stream::huffyuv_extract_tables(const std::uint8_t *chunkdata, std::uint32_t size)
{
- avi_file *newfile = nullptr;
- file_error filerr;
- avi_stream *stream;
- avi_error avierr;
- UINT64 length;
+ const std::uint8_t *const chunkend = chunkdata + size;
- /* validate video info */
- if ((info->video_format != 0 && info->video_format != FORMAT_UYVY && info->video_format != FORMAT_VYUY && info->video_format != FORMAT_YUY2) ||
- info->video_width == 0 ||
- info->video_height == 0 ||
- info->video_depth == 0 || info->video_depth % 8 != 0)
- return AVIERR_UNSUPPORTED_VIDEO_FORMAT;
+ /* allocate memory for the data */
+ std::unique_ptr<huffyuv_data> huffyuv;
+ try { huffyuv = std::make_unique<huffyuv_data>(); }
+ catch (...) { return avi_file::error::NO_MEMORY; }
- /* validate audio info */
- if (info->audio_format != 0 ||
- info->audio_channels > MAX_SOUND_CHANNELS ||
- info->audio_samplebits != 16)
- return AVIERR_UNSUPPORTED_AUDIO_FORMAT;
+ /* extract predictor information */
+ if (&chunkdata[40] >= chunkend)
+ return avi_file::error::INVALID_DATA;
+ huffyuv->predictor = chunkdata[40];
- /* allocate the file */
- newfile = (avi_file *)malloc(sizeof(*newfile));
- if (newfile == nullptr)
- return AVIERR_NO_MEMORY;
- memset(newfile, 0, sizeof(*newfile));
- newfile->type = FILETYPE_CREATE;
+ /* make sure it's the left predictor */
+ if ((huffyuv->predictor & ~HUFFYUV_PREDICT_DECORR) != HUFFYUV_PREDICT_LEFT)
+ return avi_file::error::UNSUPPORTED_VIDEO_FORMAT;
- /* open the file */
- filerr = osd_open(filename, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS, &newfile->file, &length);
- if (filerr != FILERR_NONE)
+ /* make sure it's 16bpp YUV data */
+ if (chunkdata[41] != 16)
+ return avi_file::error::UNSUPPORTED_VIDEO_FORMAT;
+ chunkdata += 44;
+
+ /* loop over tables */
+ for (int tabnum = 0; tabnum < 3; tabnum++)
{
- avierr = AVIERR_CANT_OPEN_FILE;
- goto error;
+ huffyuv_table &table = huffyuv->table[tabnum];
+ std::uint32_t curbits, bitadd;
+ std::uint16_t bitsat16 = 0;
+ int offset = 0, bits;
+
+ /* loop until we populate the whole table */
+ while (offset < 256)
+ {
+ int data, shift, count, i;
+
+ /* extract the next run */
+ if (chunkdata >= chunkend)
+ return avi_file::error::INVALID_DATA;
+ data = *chunkdata++;
+ shift = data & 0x1f;
+ count = data >> 5;
+
+ /* zero count means next whole byte is a count */
+ if (count == 0)
+ {
+ if (chunkdata >= chunkend)
+ return avi_file::error::INVALID_DATA;
+ count = *chunkdata++;
+ }
+ for (i = 0; i < count; i++)
+ table.shift[offset++] = shift;
+ }
+
+ /* now determine bit patterns and masks */
+ curbits = 0;
+ for (bits = 31; bits >= 0; bits--)
+ {
+ bitadd = 1 << (32 - bits);
+
+ /* make sure we've cleared out all the bits below */
+ if ((curbits & (bitadd - 1)) != 0)
+ return avi_file::error::INVALID_DATA;
+
+ /* find all entries with this shift count and assign them */
+ for (offset = 0; offset < 256; offset++)
+ if (table.shift[offset] == bits)
+ {
+ table.bits[offset] = curbits;
+ table.mask[offset] = ~(bitadd - 1);
+ curbits += bitadd;
+ }
+
+ /* remember the bit pattern when we complete all the 17-bit codes */
+ if (bits == 17)
+ bitsat16 = curbits >> 16;
+ }
+
+ /* allocate the number of extra lookup tables we need */
+ if (bitsat16 > 0)
+ {
+ try { table.extralookup.resize(bitsat16 * 65536); }
+ catch (...) { return avi_file::error::NO_MEMORY; }
+ for (offset = 0; offset < bitsat16; offset++)
+ table.baselookup[offset] = (offset << 8) | 0;
+ }
+
+ /* then create lookup tables */
+ for (offset = 0; offset < 256; offset++)
+ if (table.shift[offset] > 16)
+ {
+ std::uint16_t *tablebase = &table.extralookup[(table.bits[offset] >> 16) * 65536];
+ std::uint32_t start = table.bits[offset] & 0xffff;
+ std::uint32_t end = start + ((1 << (32 - table.shift[offset])) - 1);
+ while (start <= end)
+ tablebase[start++] = (offset << 8) | (table.shift[offset] - 16);
+ }
+ else if (table.shift[offset] > 0)
+ {
+ std::uint32_t start = table.bits[offset] >> 16;
+ std::uint32_t end = start + ((1 << (16 - table.shift[offset])) - 1);
+ while (start <= end)
+ table.baselookup[start++] = (offset << 8) | table.shift[offset];
+ }
}
- /* copy the movie info */
- newfile->info = *info;
- newfile->info.video_numsamples = 0;
- newfile->info.audio_numsamples = 0;
+ m_huffyuv = std::move(huffyuv);
+ return avi_file::error::NONE;
+}
+
- /* allocate two streams */
- newfile->stream = (avi_stream *)malloc(2 * sizeof(newfile->stream[0]));
- if (newfile->stream == nullptr)
+/*-------------------------------------------------
+ huffyuv_decompress_to_yuy16 - decompress a
+ HuffYUV-encoded frame to a YUY16 bitmap
+-------------------------------------------------*/
+
+/**
+ * @fn static avi_error huffyuv_decompress_to_yuy16(avi_stream *stream, const std::uint8_t *data, std::uint32_t numbytes, bitmap_yuy16 &bitmap)
+ *
+ * @brief Huffyuv decompress to yuy 16.
+ *
+ * @param [in,out] stream If non-null, the stream.
+ * @param data The data.
+ * @param numbytes The numbytes.
+ * @param [in,out] bitmap The bitmap.
+ *
+ * @return An avi_error.
+ */
+
+avi_file::error avi_stream::huffyuv_decompress_to_yuy16(const std::uint8_t *data, std::uint32_t numbytes, bitmap_yuy16 &bitmap) const
+{
+ int prevlines = (m_height > 288) ? 2 : 1;
+ std::uint8_t lastprevy = 0, lastprevcb = 0, lastprevcr = 0;
+ std::uint8_t lasty = 0, lastcb = 0, lastcr = 0;
+ std::uint8_t bitsinbuffer = 0;
+ std::uint32_t bitbuffer = 0;
+ std::uint32_t dataoffs = 0;
+ int x, y;
+
+ /* compressed video */
+ for (y = 0; y < m_height; y++)
{
- avierr = AVIERR_NO_MEMORY;
- goto error;
+ std::uint16_t *dest = &bitmap.pix16(y);
+
+ /* handle the first four bytes independently */
+ x = 0;
+ if (y == 0)
+ {
+ /* first DWORD is stored as YUY2 */
+ lasty = data[dataoffs++];
+ lastcb = data[dataoffs++];
+ *dest++ = (lasty << 8) | lastcb;
+ lasty = data[dataoffs++];
+ lastcr = data[dataoffs++];
+ *dest++ = (lasty << 8) | lastcr;
+ x = 2;
+ }
+
+ /* loop over pixels */
+ for ( ; x < m_width; x++)
+ {
+ huffyuv_table const &ytable = m_huffyuv->table[0];
+ huffyuv_table const &ctable = m_huffyuv->table[1 + (x & 1)];
+ std::uint16_t huffdata;
+ int shift;
+
+ /* fill up the buffer; they store little-endian DWORDs, so we XOR with 3 */
+ while (bitsinbuffer <= 24 && dataoffs < numbytes)
+ {
+ bitbuffer |= data[dataoffs++ ^ 3] << (24 - bitsinbuffer);
+ bitsinbuffer += 8;
+ }
+
+ /* look up the Y component */
+ huffdata = ytable.baselookup[bitbuffer >> 16];
+ shift = huffdata & 0xff;
+ if (shift == 0)
+ {
+ bitsinbuffer -= 16;
+ bitbuffer <<= 16;
+
+ /* fill up the buffer; they store little-endian DWORDs, so we XOR with 3 */
+ while (bitsinbuffer <= 24 && dataoffs < numbytes)
+ {
+ bitbuffer |= data[dataoffs++ ^ 3] << (24 - bitsinbuffer);
+ bitsinbuffer += 8;
+ }
+
+ huffdata = ytable.extralookup[(huffdata >> 8) * 65536 + (bitbuffer >> 16)];
+ shift = huffdata & 0xff;
+ }
+ bitsinbuffer -= shift;
+ bitbuffer <<= shift;
+ std::uint16_t const pixel = huffdata & 0xff00;
+
+ /* fill up the buffer; they store little-endian DWORDs, so we XOR with 3 */
+ while (bitsinbuffer <= 24 && dataoffs < numbytes)
+ {
+ bitbuffer |= data[dataoffs++ ^ 3] << (24 - bitsinbuffer);
+ bitsinbuffer += 8;
+ }
+
+ /* look up the Cb/Cr component */
+ huffdata = ctable.baselookup[bitbuffer >> 16];
+ shift = huffdata & 0xff;
+ if (shift == 0)
+ {
+ bitsinbuffer -= 16;
+ bitbuffer <<= 16;
+
+ /* fill up the buffer; they store little-endian DWORDs, so we XOR with 3 */
+ while (bitsinbuffer <= 24 && dataoffs < numbytes)
+ {
+ bitbuffer |= data[dataoffs++ ^ 3] << (24 - bitsinbuffer);
+ bitsinbuffer += 8;
+ }
+
+ huffdata = ctable.extralookup[(huffdata >> 8) * 65536 + (bitbuffer >> 16)];
+ shift = huffdata & 0xff;
+ }
+ bitsinbuffer -= shift;
+ bitbuffer <<= shift;
+ *dest++ = pixel | (huffdata >> 8);
+ }
}
- memset(newfile->stream, 0, 2 * sizeof(newfile->stream[0]));
-
- /* initialize the video track */
- stream = &newfile->stream[newfile->streams++];
- stream->type = STREAMTYPE_VIDS;
- stream->format = newfile->info.video_format;
- stream->rate = newfile->info.video_timescale;
- stream->scale = newfile->info.video_sampletime;
- stream->width = newfile->info.video_width;
- stream->height = newfile->info.video_height;
- stream->depth = newfile->info.video_depth;
-
- /* initialize the audio track */
- if (newfile->info.audio_channels > 0)
+
+ /* apply deltas */
+ lastprevy = lastprevcb = lastprevcr = 0;
+ for (y = 0; y < m_height; y++)
{
- stream = &newfile->stream[newfile->streams++];
- stream->type = STREAMTYPE_AUDS;
- stream->format = newfile->info.audio_format;
- stream->rate = newfile->info.audio_timescale;
- stream->scale = newfile->info.audio_sampletime;
- stream->channels = newfile->info.audio_channels;
- stream->samplebits = newfile->info.audio_samplebits;
- stream->samplerate = newfile->info.audio_samplerate;
-
- /* initialize the sound buffering */
- avierr = soundbuf_initialize(newfile);
- if (avierr != AVIERR_NONE)
- goto error;
- }
+ std::uint16_t *prevrow = &bitmap.pix16(y - prevlines);
+ std::uint16_t *dest = &bitmap.pix16(y);
- /* write the initial headers */
- avierr = write_initial_headers(newfile);
- if (avierr != AVIERR_NONE)
- goto error;
+ /* handle the first four bytes independently */
+ x = 0;
+ if (y == 0)
+ {
+ /* lasty, lastcr, lastcb are set up previously */
+ x = 2;
+ }
- *file = newfile;
- return AVIERR_NONE;
+ /* left predict or gradient predict */
+ if ((m_huffyuv->predictor & ~HUFFYUV_PREDICT_DECORR) == HUFFYUV_PREDICT_LEFT ||
+ ((m_huffyuv->predictor & ~HUFFYUV_PREDICT_DECORR) == HUFFYUV_PREDICT_GRADIENT))
+ {
+ /* first do left deltas */
+ for ( ; x < m_width; x += 2)
+ {
+ std::uint16_t pixel0 = dest[x + 0];
+ std::uint16_t pixel1 = dest[x + 1];
-error:
- /* clean up after an error */
- if (newfile != nullptr)
- {
- if (newfile->stream != nullptr)
- free(newfile->stream);
- if (newfile->file != nullptr)
+ lasty += pixel0 >> 8;
+ lastcb += pixel0;
+ dest[x + 0] = (lasty << 8) | lastcb;
+
+ lasty += pixel1 >> 8;
+ lastcr += pixel1;
+ dest[x + 1] = (lasty << 8) | lastcr;
+ }
+
+ /* for gradient, we then add in the previous row */
+ if ((m_huffyuv->predictor & ~HUFFYUV_PREDICT_DECORR) == HUFFYUV_PREDICT_GRADIENT && y >= prevlines)
+ for (x = 0; x < m_width; x++)
+ {
+ std::uint16_t curpix = dest[x];
+ std::uint16_t prevpix = prevrow[x];
+ std::uint8_t ysum = (curpix >> 8) + (prevpix >> 8);
+ std::uint8_t csum = curpix + prevpix;
+ dest[x] = (ysum << 8) | csum;
+ }
+ }
+
+ /* median predict on rows > 0 */
+ else if ((m_huffyuv->predictor & ~HUFFYUV_PREDICT_DECORR) == HUFFYUV_PREDICT_MEDIAN && y >= prevlines)
{
- osd_close(newfile->file);
- osd_rmfile(filename);
+ for ( ; x < m_width; x += 2)
+ {
+ std::uint16_t prevpixel0 = prevrow[x + 0];
+ std::uint16_t prevpixel1 = prevrow[x + 1];
+ std::uint16_t pixel0 = dest[x + 0];
+ std::uint16_t pixel1 = dest[x + 1];
+ std::uint8_t a, b, c;
+
+ /* compute previous, above, and (prev + above - above-left) */
+ a = lasty;
+ b = prevpixel0 >> 8;
+ c = lastprevy;
+ lastprevy = b;
+ if (a > b) { std::uint8_t tmp = a; a = b; b = tmp; }
+ if (a > c) { std::uint8_t tmp = a; a = c; c = tmp; }
+ if (b > c) { std::uint8_t tmp = b; b = c; c = tmp; }
+ lasty = (pixel0 >> 8) + b;
+
+ /* compute previous, above, and (prev + above - above-left) */
+ a = lastcb;
+ b = prevpixel0 & 0xff;
+ c = lastprevcb;
+ lastprevcb = b;
+ if (a > b) { std::uint8_t tmp = a; a = b; b = tmp; }
+ if (a > c) { std::uint8_t tmp = a; a = c; c = tmp; }
+ if (b > c) { std::uint8_t tmp = b; b = c; c = tmp; }
+ lastcb = (pixel0 & 0xff) + b;
+ dest[x + 0] = (lasty << 8) | lastcb;
+
+ /* compute previous, above, and (prev + above - above-left) */
+ a = lasty;
+ b = prevpixel1 >> 8;
+ c = lastprevy;
+ lastprevy = b;
+ if (a > b) { std::uint8_t tmp = a; a = b; b = tmp; }
+ if (a > c) { std::uint8_t tmp = a; a = c; c = tmp; }
+ if (b > c) { std::uint8_t tmp = b; b = c; c = tmp; }
+ lasty = (pixel1 >> 8) + b;
+
+ /* compute previous, above, and (prev + above - above-left) */
+ a = lastcr;
+ b = prevpixel1 & 0xff;
+ c = lastprevcr;
+ lastprevcr = b;
+ if (a > b) { std::uint8_t tmp = a; a = b; b = tmp; }
+ if (a > c) { std::uint8_t tmp = a; a = c; c = tmp; }
+ if (b > c) { std::uint8_t tmp = b; b = c; c = tmp; }
+ lastcr = (pixel1 & 0xff) + b;
+ dest[x + 1] = (lasty << 8) | lastcr;
+ }
}
- free(newfile);
}
- return avierr;
+
+ return avi_file::error::NONE;
}
@@ -1029,73 +1481,46 @@ error:
* @return An avi_error.
*/
-avi_error avi_close(avi_file *file)
+avi_file_impl::~avi_file_impl()
{
- avi_error avierr = AVIERR_NONE;
- int strnum;
+ error avierr = error::NONE;
/* if we're creating a new file, finalize it by writing out the non-media chunks */
- if (file->type == FILETYPE_CREATE)
+ if (m_type == FILETYPE_CREATE)
{
/* flush any pending sound data */
- avierr = soundbuf_flush(file, FALSE);
+ avierr = soundbuf_flush(false);
/* close the movi chunk */
- if (avierr == AVIERR_NONE)
- avierr = chunk_close(file);
+ if (avierr == error::NONE)
+ avierr = chunk_close();
/* if this is the first RIFF chunk, write an idx1 */
- if (avierr == AVIERR_NONE && file->riffbase == 0)
- avierr = write_idx1_chunk(file);
+ if (avierr == error::NONE && m_riffbase == 0)
+ avierr = write_idx1_chunk();
/* update the strh and indx chunks for each stream */
- for (strnum = 0; strnum < file->streams; strnum++)
+ for (int strnum = 0; strnum < m_streams.size(); strnum++)
{
- if (avierr == AVIERR_NONE)
- avierr = write_strh_chunk(file, &file->stream[strnum], FALSE);
- if (avierr == AVIERR_NONE)
- avierr = write_indx_chunk(file, &file->stream[strnum], FALSE);
+ if (avierr == error::NONE)
+ avierr = write_strh_chunk(m_streams[strnum], false);
+ if (avierr == error::NONE)
+ avierr = write_indx_chunk(m_streams[strnum], false);
}
/* update the avih chunk */
- if (avierr == AVIERR_NONE)
- avierr = write_avih_chunk(file, FALSE);
+ if (avierr == error::NONE)
+ avierr = write_avih_chunk(false);
/* close the RIFF chunk */
- if (avierr == AVIERR_NONE)
- avierr = chunk_close(file);
+ if (avierr == error::NONE)
+ avierr = chunk_close();
}
/* close the file */
- osd_close(file->file);
-
- /* free the stream-specific data */
- for (strnum = 0; strnum < file->streams; strnum++)
- {
- avi_stream *stream = &file->stream[strnum];
- if (stream->huffyuv != nullptr)
- {
- huffyuv_data *huffyuv = stream->huffyuv;
- int table;
+ m_file.reset();
- for (table = 0; table < ARRAY_LENGTH(huffyuv->table); table++)
- if (huffyuv->table[table].extralookup != nullptr)
- free(huffyuv->table[table].extralookup);
- free(huffyuv);
- }
- if (stream->chunk != nullptr)
- free(stream->chunk);
- }
-
- /* free the file itself */
- if (file->soundbuf != nullptr)
- free(file->soundbuf);
- if (file->stream != nullptr)
- free(file->stream);
- if (file->tempbuffer != nullptr)
- free(file->tempbuffer);
- free(file);
- return avierr;
+ //return avierr;
}
@@ -1111,55 +1536,14 @@ avi_error avi_close(avi_file *file)
* @param [in,out] file If non-null, the file.
*/
-void avi_printf_chunks(avi_file *file)
-{
- printf_chunk_recursive(file, &file->rootchunk, 0);
-}
-
-
-/*-------------------------------------------------
- avi_error_string - get the error string for
- an avi_error
--------------------------------------------------*/
-
-/**
- * @fn const char *avi_error_string(avi_error err)
- *
- * @brief Avi error string.
- *
- * @param err The error.
- *
- * @return null if it fails, else a char*.
- */
-
-const char *avi_error_string(avi_error err)
+void avi_file_impl::printf_chunks()
{
- switch (err)
- {
- case AVIERR_NONE: return "success";
- case AVIERR_END: return "hit end of file";
- case AVIERR_INVALID_DATA: return "invalid data";
- case AVIERR_NO_MEMORY: return "out of memory";
- case AVIERR_READ_ERROR: return "read error";
- case AVIERR_WRITE_ERROR: return "write error";
- case AVIERR_STACK_TOO_DEEP: return "stack overflow";
- case AVIERR_UNSUPPORTED_FEATURE: return "unsupported feature";
- case AVIERR_CANT_OPEN_FILE: return "unable to open file";
- case AVIERR_INCOMPATIBLE_AUDIO_STREAMS: return "found incompatible audio streams";
- case AVIERR_INVALID_SAMPLERATE: return "found invalid sample rate";
- case AVIERR_INVALID_STREAM: return "invalid stream";
- case AVIERR_INVALID_FRAME: return "invalid frame index";
- case AVIERR_INVALID_BITMAP: return "invalid bitmap";
- case AVIERR_UNSUPPORTED_VIDEO_FORMAT: return "unsupported video format";
- case AVIERR_UNSUPPORTED_AUDIO_FORMAT: return "unsupported audio format";
- case AVIERR_EXCEEDED_SOUND_BUFFER: return "sound buffer overflow";
- default: return "undocumented error";
- }
+ printf_chunk_recursive(&m_rootchunk, 0);
}
/*-------------------------------------------------
- avi_get_movie_info - return a pointer to the
+ get_movie_info - return a pointer to the
movie info
-------------------------------------------------*/
@@ -1173,9 +1557,9 @@ const char *avi_error_string(avi_error err)
* @return null if it fails, else an avi_movie_info*.
*/
-const avi_movie_info *avi_get_movie_info(avi_file *file)
+avi_file::movie_info const &avi_file_impl::get_movie_info() const
{
- return &file->info;
+ return m_info;
}
@@ -1185,19 +1569,19 @@ const avi_movie_info *avi_get_movie_info(avi_file *file)
-------------------------------------------------*/
/**
- * @fn UINT32 avi_first_sample_in_frame(avi_file *file, UINT32 framenum)
+ * @fn std::uint32_t avi_first_sample_in_frame(avi_file *file, std::uint32_t framenum)
*
* @brief Avi first sample in frame.
*
* @param [in,out] file If non-null, the file.
* @param framenum The framenum.
*
- * @return An UINT32.
+ * @return An std::uint32_t.
*/
-UINT32 avi_first_sample_in_frame(avi_file *file, UINT32 framenum)
+std::uint32_t avi_file_impl::first_sample_in_frame(std::uint32_t framenum) const
{
- return framenum_to_samplenum(file, framenum);
+ return framenum_to_samplenum(framenum);
}
@@ -1208,7 +1592,7 @@ UINT32 avi_first_sample_in_frame(avi_file *file, UINT32 framenum)
-------------------------------------------------*/
/**
- * @fn avi_error avi_read_video_frame(avi_file *file, UINT32 framenum, bitmap_yuy16 &bitmap)
+ * @fn avi_error avi_read_video_frame(avi_file *file, std::uint32_t framenum, bitmap_yuy16 &bitmap)
*
* @brief Avi read video frame.
*
@@ -1219,54 +1603,51 @@ UINT32 avi_first_sample_in_frame(avi_file *file, UINT32 framenum)
* @return An avi_error.
*/
-avi_error avi_read_video_frame(avi_file *file, UINT32 framenum, bitmap_yuy16 &bitmap)
+avi_file::error avi_file_impl::read_video_frame(std::uint32_t framenum, bitmap_yuy16 &bitmap)
{
- avi_error avierr = AVIERR_NONE;
- UINT32 bytes_read, chunkid;
- file_error filerr;
- avi_stream *stream;
-
/* get the video stream */
- stream = get_video_stream(file);
- if (stream == nullptr)
- return AVIERR_INVALID_STREAM;
+ avi_stream *const stream = get_video_stream();
+ if (!stream)
+ return error::INVALID_STREAM;
/* validate our ability to handle the data */
- if (stream->format != FORMAT_UYVY && stream->format != FORMAT_VYUY && stream->format != FORMAT_YUY2 && stream->format != FORMAT_HFYU)
- return AVIERR_UNSUPPORTED_VIDEO_FORMAT;
+ if (stream->format() != FORMAT_UYVY && stream->format() != FORMAT_VYUY && stream->format() != FORMAT_YUY2 && stream->format() != FORMAT_HFYU)
+ return error::UNSUPPORTED_VIDEO_FORMAT;
/* assume one chunk == one frame */
- if (framenum >= stream->chunks)
- return AVIERR_INVALID_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 AVIERR_INVALID_BITMAP;
+ if (bitmap.width() < stream->width() || bitmap.height() < stream->height())
+ return error::INVALID_BITMAP;
/* expand the tempbuffer to hold the data if necessary */
- avierr = expand_tempbuffer(file, stream->chunk[framenum].length);
- if (avierr != AVIERR_NONE)
+ error avierr = error::NONE;
+ avierr = expand_tempbuffer(stream->chunk(framenum).length);
+ if (avierr != error::NONE)
return avierr;
/* read in the data */
- filerr = osd_read(file->file, file->tempbuffer, stream->chunk[framenum].offset, stream->chunk[framenum].length, &bytes_read);
- if (filerr != FILERR_NONE || bytes_read != stream->chunk[framenum].length)
- return AVIERR_READ_ERROR;
+ 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 */
- chunkid = fetch_32bits(&file->tempbuffer[0]);
- if (chunkid == get_chunkid_for_stream(file, stream))
+ std::uint32_t const chunkid = fetch_32bits(&m_tempbuffer[0]);
+ if (chunkid == get_chunkid_for_stream(stream))
{
/* HuffYUV-compressed */
- if (stream->format == FORMAT_HFYU)
- avierr = huffyuv_decompress_to_yuy16(stream, file->tempbuffer + 8, stream->chunk[framenum].length - 8, bitmap);
+ if (stream->format() == FORMAT_HFYU)
+ avierr = stream->huffyuv_decompress_to_yuy16(&m_tempbuffer[8], stream->chunk(framenum).length - 8, bitmap);
/* other YUV-compressed */
else
- avierr = yuv_decompress_to_yuy16(stream, file->tempbuffer + 8, stream->chunk[framenum].length - 8, bitmap);
+ avierr = stream->yuv_decompress_to_yuy16(&m_tempbuffer[8], stream->chunk(framenum).length - 8, bitmap);
}
else
- avierr = AVIERR_INVALID_DATA;
+ avierr = error::INVALID_DATA;
return avierr;
}
@@ -1278,7 +1659,7 @@ avi_error avi_read_video_frame(avi_file *file, UINT32 framenum, bitmap_yuy16 &bi
-------------------------------------------------*/
/**
- * @fn avi_error avi_read_sound_samples(avi_file *file, int channel, UINT32 firstsample, UINT32 numsamples, INT16 *output)
+ * @fn avi_error avi_read_sound_samples(avi_file *file, int channel, std::uint32_t firstsample, std::uint32_t numsamples, std::int16_t *output)
*
* @brief Avi read sound samples.
*
@@ -1291,95 +1672,90 @@ avi_error avi_read_video_frame(avi_file *file, UINT32 framenum, bitmap_yuy16 &bi
* @return An avi_error.
*/
-avi_error avi_read_sound_samples(avi_file *file, int channel, UINT32 firstsample, UINT32 numsamples, INT16 *output)
+avi_file::error avi_file_impl::read_sound_samples(int channel, std::uint32_t firstsample, std::uint32_t numsamples, std::int16_t *output)
{
- avi_error avierr = AVIERR_NONE;
- UINT32 bytes_per_sample;
- file_error filerr;
- avi_stream *stream;
- int offset = 0;
-
/* get the audio stream */
- stream = get_audio_stream(file, channel, &offset);
- if (stream == nullptr)
- return AVIERR_INVALID_STREAM;
+ int offset = 0;
+ avi_stream *const stream = get_audio_stream(channel, offset);
+ if (!stream)
+ return error::INVALID_STREAM;
/* validate our ability to handle the data */
- if (stream->format != 0 || (stream->samplebits != 8 && stream->samplebits != 16))
- return AVIERR_UNSUPPORTED_AUDIO_FORMAT;
+ if (stream->format() != 0 || (stream->samplebits() != 8 && stream->samplebits() != 16))
+ return error::UNSUPPORTED_AUDIO_FORMAT;
/* verify we are in range */
- if (firstsample >= stream->samples)
- return AVIERR_INVALID_FRAME;
- if (firstsample + numsamples > stream->samples)
- numsamples = stream->samples - firstsample;
+ if (firstsample >= stream->samples())
+ return error::INVALID_FRAME;
+ if (firstsample + numsamples > stream->samples())
+ numsamples = stream->samples() - firstsample;
/* determine bytes per sample */
- bytes_per_sample = (stream->samplebits / 8) * stream->channels;
+ std::uint32_t const bytes_per_sample = stream->bytes_per_sample();
/* loop until all samples have been extracted */
while (numsamples > 0)
{
- UINT32 chunkbase = 0, chunkend = 0, chunkid;
- UINT32 bytes_read, samples_this_chunk;
+ std::uint32_t chunkbase = 0, chunkend = 0, chunkid;
+ std::uint32_t bytes_read, samples_this_chunk;
int chunknum, sampnum;
/* locate the chunk with the first sample */
- for (chunknum = 0; chunknum < stream->chunks; chunknum++)
+ for (chunknum = 0; chunknum < stream->chunks(); chunknum++)
{
- chunkend = chunkbase + (stream->chunk[chunknum].length - 8) / bytes_per_sample;
+ chunkend = chunkbase + (stream->chunk(chunknum).length - 8) / bytes_per_sample;
if (firstsample < chunkend)
break;
chunkbase = chunkend;
}
/* if we hit the end, fill the rest with silence */
- if (chunknum == stream->chunks)
+ if (chunknum == stream->chunks())
{
- memset(output, 0, numsamples * 2);
+ std::memset(output, 0, numsamples * 2);
break;
}
/* expand the tempbuffer to hold the data if necessary */
- avierr = expand_tempbuffer(file, stream->chunk[chunknum].length);
- if (avierr != AVIERR_NONE)
+ error avierr = expand_tempbuffer(stream->chunk(chunknum).length);
+ if (avierr != error::NONE)
return avierr;
/* read in the data */
- filerr = osd_read(file->file, file->tempbuffer, stream->chunk[chunknum].offset, stream->chunk[chunknum].length, &bytes_read);
- if (filerr != FILERR_NONE || bytes_read != stream->chunk[chunknum].length)
- return AVIERR_READ_ERROR;
+ auto const filerr = m_file->read(&m_tempbuffer[0], stream->chunk(chunknum).offset, stream->chunk(chunknum).length, bytes_read);
+ if (filerr != osd_file::error::NONE || bytes_read != stream->chunk(chunknum).length)
+ return error::READ_ERROR;
/* validate this is good data */
- chunkid = fetch_32bits(&file->tempbuffer[0]);
- if (chunkid != get_chunkid_for_stream(file, stream))
- return AVIERR_INVALID_DATA;
+ chunkid = fetch_32bits(&m_tempbuffer[0]);
+ if (chunkid != get_chunkid_for_stream(stream))
+ return error::INVALID_DATA;
/* determine how many samples to copy */
samples_this_chunk = chunkend - firstsample;
- samples_this_chunk = MIN(samples_this_chunk, numsamples);
+ samples_this_chunk = (std::min)(samples_this_chunk, numsamples);
/* extract 16-bit samples from the chunk */
- if (stream->samplebits == 16)
+ if (stream->samplebits() == 16)
{
- const INT16 *base = (const INT16 *)(file->tempbuffer + 8);
- base += stream->channels * (firstsample - chunkbase) + offset;
+ const std::int16_t *base = reinterpret_cast<const std::int16_t *>(&m_tempbuffer[8]);
+ base += stream->channels() * (firstsample - chunkbase) + offset;
for (sampnum = 0; sampnum < samples_this_chunk; sampnum++)
{
*output++ = LITTLE_ENDIANIZE_INT16(*base);
- base += stream->channels;
+ base += stream->channels();
}
}
/* extract 8-bit samples from the chunk */
- else if (stream->samplebits == 8)
+ else if (stream->samplebits() == 8)
{
- const UINT8 *base = (const UINT8 *)(file->tempbuffer + 8);
- base += stream->channels * (firstsample - chunkbase) + offset;
+ const std::uint8_t *base = &m_tempbuffer[8];
+ base += stream->channels() * (firstsample - chunkbase) + offset;
for (sampnum = 0; sampnum < samples_this_chunk; sampnum++)
{
*output++ = (*base << 8) - 0x8000;
- base += stream->channels;
+ base += stream->channels();
}
}
@@ -1388,7 +1764,7 @@ avi_error avi_read_sound_samples(avi_file *file, int channel, UINT32 firstsample
numsamples -= samples_this_chunk;
}
- return avierr;
+ return error::NONE;
}
@@ -1408,45 +1784,45 @@ avi_error avi_read_sound_samples(avi_file *file, int channel, UINT32 firstsample
* @return An avi_error.
*/
-avi_error avi_append_video_frame(avi_file *file, bitmap_yuy16 &bitmap)
+avi_file::error avi_file_impl::append_video_frame(bitmap_yuy16 &bitmap)
{
- avi_stream *stream = get_video_stream(file);
- avi_error avierr;
- UINT32 maxlength;
+ avi_stream *const stream = get_video_stream();
+ error avierr;
+ std::uint32_t maxlength;
/* validate our ability to handle the data */
- if (stream->format != FORMAT_UYVY && stream->format != FORMAT_VYUY && stream->format != FORMAT_YUY2 && stream->format != FORMAT_HFYU)
- return AVIERR_UNSUPPORTED_VIDEO_FORMAT;
+ if (stream->format() != FORMAT_UYVY && stream->format() != FORMAT_VYUY && stream->format() != FORMAT_YUY2 && stream->format() != FORMAT_HFYU)
+ return error::UNSUPPORTED_VIDEO_FORMAT;
/* write out any sound data first */
- avierr = soundbuf_write_chunk(file, stream->chunks);
- if (avierr != AVIERR_NONE)
+ avierr = soundbuf_write_chunk(stream->chunks());
+ if (avierr != error::NONE)
return avierr;
/* make sure we have enough room */
- maxlength = 2 * stream->width * stream->height;
- avierr = expand_tempbuffer(file, maxlength);
- if (avierr != AVIERR_NONE)
+ maxlength = 2 * stream->width() * stream->height();
+ avierr = expand_tempbuffer(maxlength);
+ if (avierr != error::NONE)
return avierr;
/* now compress the data */
- avierr = yuy16_compress_to_yuy(stream, bitmap, file->tempbuffer, maxlength);
- if (avierr != AVIERR_NONE)
+ avierr = stream->yuy16_compress_to_yuy(bitmap, &m_tempbuffer[0], maxlength);
+ if (avierr != error::NONE)
return avierr;
/* write the data */
- avierr = chunk_write(file, get_chunkid_for_stream(file, stream), file->tempbuffer, maxlength);
- if (avierr != AVIERR_NONE)
+ avierr = chunk_write(get_chunkid_for_stream(stream), &m_tempbuffer[0], maxlength);
+ if (avierr != error::NONE)
return avierr;
/* set the info for this new chunk */
- avierr = set_stream_chunk_info(stream, stream->chunks, file->writeoffs - maxlength - 8, maxlength + 8);
- if (avierr != AVIERR_NONE)
+ avierr = stream->set_chunk_info(stream->chunks(), m_writeoffs - maxlength - 8, maxlength + 8);
+ if (avierr != error::NONE)
return avierr;
- stream->samples = file->info.video_numsamples = stream->chunks;
+ stream->set_samples(m_info.video_numsamples = stream->chunks());
- return AVIERR_NONE;
+ return error::NONE;
}
@@ -1466,49 +1842,49 @@ avi_error avi_append_video_frame(avi_file *file, bitmap_yuy16 &bitmap)
* @return An avi_error.
*/
-avi_error avi_append_video_frame(avi_file *file, bitmap_rgb32 &bitmap)
+avi_file::error avi_file_impl::append_video_frame(bitmap_rgb32 &bitmap)
{
- avi_stream *stream = get_video_stream(file);
- avi_error avierr;
- UINT32 maxlength;
+ avi_stream *const stream = get_video_stream();
+ error avierr;
+ std::uint32_t maxlength;
/* validate our ability to handle the data */
- if (stream->format != 0)
- return AVIERR_UNSUPPORTED_VIDEO_FORMAT;
+ if (stream->format() != 0)
+ return error::UNSUPPORTED_VIDEO_FORMAT;
/* depth must be 24 */
- if (stream->depth != 24)
- return AVIERR_UNSUPPORTED_VIDEO_FORMAT;
+ if (stream->depth() != 24)
+ return error::UNSUPPORTED_VIDEO_FORMAT;
/* write out any sound data first */
- avierr = soundbuf_write_chunk(file, stream->chunks);
- if (avierr != AVIERR_NONE)
+ avierr = soundbuf_write_chunk(stream->chunks());
+ if (avierr != error::NONE)
return avierr;
/* make sure we have enough room */
- maxlength = 3 * stream->width * stream->height;
- avierr = expand_tempbuffer(file, maxlength);
- if (avierr != AVIERR_NONE)
+ maxlength = 3 * stream->width() * stream->height();
+ avierr = expand_tempbuffer(maxlength);
+ if (avierr != error::NONE)
return avierr;
/* copy the RGB data to the destination */
- avierr = rgb32_compress_to_rgb(stream, bitmap, file->tempbuffer, maxlength);
- if (avierr != AVIERR_NONE)
+ avierr = stream->rgb32_compress_to_rgb(bitmap, &m_tempbuffer[0], maxlength);
+ if (avierr != error::NONE)
return avierr;
/* write the data */
- avierr = chunk_write(file, get_chunkid_for_stream(file, stream), file->tempbuffer, maxlength);
- if (avierr != AVIERR_NONE)
+ avierr = chunk_write(get_chunkid_for_stream(stream), &m_tempbuffer[0], maxlength);
+ if (avierr != error::NONE)
return avierr;
/* set the info for this new chunk */
- avierr = set_stream_chunk_info(stream, stream->chunks, file->writeoffs - maxlength - 8, maxlength + 8);
- if (avierr != AVIERR_NONE)
+ avierr = stream->set_chunk_info(stream->chunks(), m_writeoffs - maxlength - 8, maxlength + 8);
+ if (avierr != error::NONE)
return avierr;
- stream->samples = file->info.video_numsamples = stream->chunks;
+ stream->set_samples(m_info.video_numsamples = stream->chunks());
- return AVIERR_NONE;
+ return error::NONE;
}
@@ -1518,7 +1894,7 @@ avi_error avi_append_video_frame(avi_file *file, bitmap_rgb32 &bitmap)
-------------------------------------------------*/
/**
- * @fn avi_error avi_append_sound_samples(avi_file *file, int channel, const INT16 *samples, UINT32 numsamples, UINT32 sampleskip)
+ * @fn avi_error avi_append_sound_samples(avi_file *file, int channel, const std::int16_t *samples, std::uint32_t numsamples, std::uint32_t sampleskip)
*
* @brief Avi append sound samples.
*
@@ -1531,27 +1907,27 @@ avi_error avi_append_video_frame(avi_file *file, bitmap_rgb32 &bitmap)
* @return An avi_error.
*/
-avi_error avi_append_sound_samples(avi_file *file, int channel, const INT16 *samples, UINT32 numsamples, UINT32 sampleskip)
+avi_file::error avi_file_impl::append_sound_samples(int channel, const std::int16_t *samples, std::uint32_t numsamples, std::uint32_t sampleskip)
{
- UINT32 sampoffset = file->soundbuf_chansamples[channel];
- UINT32 sampnum;
+ std::uint32_t sampoffset = m_soundbuf_chansamples[channel];
+ std::uint32_t sampnum;
/* see if we have enough room in the buffer */
- if (sampoffset + numsamples > file->soundbuf_samples)
- return AVIERR_EXCEEDED_SOUND_BUFFER;
+ if (sampoffset + numsamples > m_soundbuf_samples)
+ return error::EXCEEDED_SOUND_BUFFER;
/* append samples to the buffer in little-endian format */
for (sampnum = 0; sampnum < numsamples; sampnum++)
{
- INT16 data = *samples++;
+ std::int16_t data = *samples++;
samples += sampleskip;
data = LITTLE_ENDIANIZE_INT16(data);
- file->soundbuf[sampoffset++ * file->info.audio_channels + channel] = data;
+ m_soundbuf[sampoffset++ * m_info.audio_channels + channel] = data;
}
- file->soundbuf_chansamples[channel] = sampoffset;
+ m_soundbuf_chansamples[channel] = sampoffset;
/* flush any full sound chunks to disk */
- return soundbuf_flush(file, TRUE);
+ return soundbuf_flush(TRUE);
}
@@ -1561,7 +1937,7 @@ avi_error avi_append_sound_samples(avi_file *file, int channel, const INT16 *sam
-------------------------------------------------*/
/**
- * @fn static avi_error read_chunk_data(avi_file *file, const avi_chunk *chunk, UINT8 **buffer)
+ * @fn static avi_error read_chunk_data(avi_file *file, const avi_chunk *chunk, std::uint8_t **buffer)
*
* @brief Reads chunk data.
*
@@ -1572,26 +1948,22 @@ avi_error avi_append_sound_samples(avi_file *file, int channel, const INT16 *sam
* @return The chunk data.
*/
-static avi_error read_chunk_data(avi_file *file, const avi_chunk *chunk, UINT8 **buffer)
+avi_file::error avi_file_impl::read_chunk_data(avi_chunk const &chunk, std::unique_ptr<std::uint8_t []> &buffer)
{
- file_error filerr;
- UINT32 bytes_read;
-
/* allocate memory for the data */
- *buffer = (UINT8 *)malloc(chunk->size);
- if (*buffer == nullptr)
- return AVIERR_NO_MEMORY;
+ try { buffer.reset(new std::uint8_t[chunk.size]); }
+ catch (...) { return error::NO_MEMORY; }
/* read from the file */
- filerr = osd_read(file->file, *buffer, chunk->offset + 8, chunk->size, &bytes_read);
- if (filerr != FILERR_NONE || bytes_read != chunk->size)
+ std::uint32_t bytes_read;
+ osd_file::error const filerr = m_file->read(&buffer[0], chunk.offset + 8, chunk.size, bytes_read);
+ if (filerr != osd_file::error::NONE || bytes_read != chunk.size)
{
- free(*buffer);
- *buffer = nullptr;
- return AVIERR_READ_ERROR;
+ buffer.reset();
+ return error::READ_ERROR;
}
- return AVIERR_NONE;
+ return error::NONE;
}
@@ -1612,12 +1984,12 @@ static avi_error read_chunk_data(avi_file *file, const avi_chunk *chunk, UINT8 *
* @return The first chunk.
*/
-static avi_error get_first_chunk(avi_file *file, const avi_chunk *parent, avi_chunk *newchunk)
+avi_file::error avi_file_impl::get_first_chunk(avi_chunk const *parent, avi_chunk &newchunk)
{
- UINT64 startoffset = (parent != nullptr && parent->type != 0) ? parent->offset + 12 : 0;
+ std::uint64_t startoffset = (parent != nullptr && parent->type != 0) ? parent->offset + 12 : 0;
if (parent != nullptr && parent->type != CHUNKTYPE_LIST && parent->type != CHUNKTYPE_RIFF && parent->type != 0)
- return AVIERR_INVALID_DATA;
- return get_next_chunk_internal(file, parent, newchunk, startoffset);
+ return error::INVALID_DATA;
+ return get_next_chunk_internal(parent, newchunk, startoffset);
}
@@ -1638,10 +2010,10 @@ static avi_error get_first_chunk(avi_file *file, const avi_chunk *parent, avi_ch
* @return The next chunk.
*/
-static avi_error get_next_chunk(avi_file *file, const avi_chunk *parent, avi_chunk *newchunk)
+avi_file::error avi_file_impl::get_next_chunk(avi_chunk const *parent, avi_chunk &newchunk)
{
- UINT64 nextoffset = newchunk->offset + 8 + newchunk->size + (newchunk->size & 1);
- return get_next_chunk_internal(file, parent, newchunk, nextoffset);
+ std::uint64_t nextoffset = newchunk.offset + 8 + newchunk.size + (newchunk.size & 1);
+ return get_next_chunk_internal(parent, newchunk, nextoffset);
}
@@ -1651,7 +2023,7 @@ static avi_error get_next_chunk(avi_file *file, const avi_chunk *parent, avi_chu
-------------------------------------------------*/
/**
- * @fn static avi_error find_first_chunk(avi_file *file, UINT32 findme, const avi_chunk *container, avi_chunk *result)
+ * @fn static avi_error find_first_chunk(avi_file *file, std::uint32_t findme, const avi_chunk *container, avi_chunk *result)
*
* @brief Searches for the first chunk.
*
@@ -1663,13 +2035,13 @@ static avi_error get_next_chunk(avi_file *file, const avi_chunk *parent, avi_chu
* @return The found chunk.
*/
-static avi_error find_first_chunk(avi_file *file, UINT32 findme, const avi_chunk *container, avi_chunk *result)
+avi_file::error avi_file_impl::find_first_chunk(std::uint32_t findme, const avi_chunk *container, avi_chunk &result)
{
- avi_error avierr;
+ error avierr;
- for (avierr = get_first_chunk(file, container, result); avierr == AVIERR_NONE; avierr = get_next_chunk(file, container, result))
- if (result->type == findme)
- return AVIERR_NONE;
+ for (avierr = get_first_chunk(container, result); avierr == error::NONE; avierr = get_next_chunk(container, result))
+ if (result.type == findme)
+ return error::NONE;
return avierr;
}
@@ -1681,7 +2053,7 @@ static avi_error find_first_chunk(avi_file *file, UINT32 findme, const avi_chunk
-------------------------------------------------*/
/**
- * @fn static avi_error find_next_chunk(avi_file *file, UINT32 findme, const avi_chunk *container, avi_chunk *result)
+ * @fn static avi_error find_next_chunk(avi_file *file, std::uint32_t findme, const avi_chunk *container, avi_chunk *result)
*
* @brief Searches for the next chunk.
*
@@ -1693,13 +2065,13 @@ static avi_error find_first_chunk(avi_file *file, UINT32 findme, const avi_chunk
* @return The found chunk.
*/
-static avi_error find_next_chunk(avi_file *file, UINT32 findme, const avi_chunk *container, avi_chunk *result)
+avi_file::error avi_file_impl::find_next_chunk(std::uint32_t findme, const avi_chunk *container, avi_chunk &result)
{
- avi_error avierr;
+ error avierr;
- for (avierr = get_next_chunk(file, container, result); avierr == AVIERR_NONE; avierr = get_next_chunk(file, container, result))
- if (result->type == findme)
- return AVIERR_NONE;
+ for (avierr = get_next_chunk(container, result); avierr == error::NONE; avierr = get_next_chunk(container, result))
+ if (result.type == findme)
+ return error::NONE;
return avierr;
}
@@ -1711,7 +2083,7 @@ static avi_error find_next_chunk(avi_file *file, UINT32 findme, const avi_chunk
-------------------------------------------------*/
/**
- * @fn static avi_error find_first_list(avi_file *file, UINT32 findme, const avi_chunk *container, avi_chunk *result)
+ * @fn static avi_error find_first_list(avi_file *file, std::uint32_t findme, const avi_chunk *container, avi_chunk *result)
*
* @brief Searches for the first list.
*
@@ -1723,13 +2095,13 @@ static avi_error find_next_chunk(avi_file *file, UINT32 findme, const avi_chunk
* @return The found list.
*/
-static avi_error find_first_list(avi_file *file, UINT32 findme, const avi_chunk *container, avi_chunk *result)
+avi_file::error avi_file_impl::find_first_list(std::uint32_t findme, const avi_chunk *container, avi_chunk &result)
{
- avi_error avierr;
+ error avierr;
- for (avierr = find_first_chunk(file, CHUNKTYPE_LIST, container, result); avierr == AVIERR_NONE; avierr = find_next_chunk(file, CHUNKTYPE_LIST, container, result))
- if (result->listtype == findme)
- return AVIERR_NONE;
+ for (avierr = find_first_chunk(CHUNKTYPE_LIST, container, result); avierr == error::NONE; avierr = find_next_chunk(CHUNKTYPE_LIST, container, result))
+ if (result.listtype == findme)
+ return error::NONE;
return avierr;
}
@@ -1741,7 +2113,7 @@ static avi_error find_first_list(avi_file *file, UINT32 findme, const avi_chunk
-------------------------------------------------*/
/**
- * @fn static avi_error find_next_list(avi_file *file, UINT32 findme, const avi_chunk *container, avi_chunk *result)
+ * @fn static avi_error find_next_list(avi_file *file, std::uint32_t findme, const avi_chunk *container, avi_chunk *result)
*
* @brief Searches for the next list.
*
@@ -1753,13 +2125,13 @@ static avi_error find_first_list(avi_file *file, UINT32 findme, const avi_chunk
* @return The found list.
*/
-static avi_error find_next_list(avi_file *file, UINT32 findme, const avi_chunk *container, avi_chunk *result)
+avi_file::error avi_file_impl::find_next_list(std::uint32_t findme, const avi_chunk *container, avi_chunk &result)
{
- avi_error avierr;
+ error avierr;
- for (avierr = find_next_chunk(file, CHUNKTYPE_LIST, container, result); avierr == AVIERR_NONE; avierr = find_next_chunk(file, CHUNKTYPE_LIST, container, result))
- if (result->listtype == findme)
- return AVIERR_NONE;
+ for (avierr = find_next_chunk(CHUNKTYPE_LIST, container, result); avierr == error::NONE; avierr = find_next_chunk(CHUNKTYPE_LIST, container, result))
+ if (result.listtype == findme)
+ return error::NONE;
return avierr;
}
@@ -1771,7 +2143,7 @@ static avi_error find_next_list(avi_file *file, UINT32 findme, const avi_chunk *
-------------------------------------------------*/
/**
- * @fn static avi_error get_next_chunk_internal(avi_file *file, const avi_chunk *parent, avi_chunk *newchunk, UINT64 offset)
+ * @fn static avi_error get_next_chunk_internal(avi_file *file, const avi_chunk *parent, avi_chunk *newchunk, std::uint64_t offset)
*
* @brief Gets the next chunk internal.
*
@@ -1783,42 +2155,42 @@ static avi_error find_next_list(avi_file *file, UINT32 findme, const avi_chunk *
* @return The next chunk internal.
*/
-static avi_error get_next_chunk_internal(avi_file *file, const avi_chunk *parent, avi_chunk *newchunk, UINT64 offset)
+avi_file::error avi_file_impl::get_next_chunk_internal(const avi_chunk *parent, avi_chunk &newchunk, std::uint64_t offset)
{
- file_error filerr;
- UINT8 buffer[12];
- UINT32 bytesread;
+ osd_file::error filerr;
+ std::uint8_t buffer[12];
+ std::uint32_t bytesread;
/* NULL parent implies the root */
if (parent == nullptr)
- parent = &file->rootchunk;
+ parent = &m_rootchunk;
/* start at the current offset */
- newchunk->offset = offset;
+ newchunk.offset = offset;
/* if we're past the bounds of the parent, bail */
- if (newchunk->offset + 8 >= parent->offset + 8 + parent->size)
- return AVIERR_END;
+ if (newchunk.offset + 8 >= parent->offset + 8 + parent->size)
+ return error::END;
/* read the header */
- filerr = osd_read(file->file, buffer, newchunk->offset, 8, &bytesread);
- if (filerr != FILERR_NONE || bytesread != 8)
- return AVIERR_INVALID_DATA;
+ filerr = m_file->read(buffer, newchunk.offset, 8, bytesread);
+ if (filerr != osd_file::error::NONE || bytesread != 8)
+ return error::INVALID_DATA;
/* fill in the new chunk */
- newchunk->type = fetch_32bits(&buffer[0]);
- newchunk->size = fetch_32bits(&buffer[4]);
+ newchunk.type = fetch_32bits(&buffer[0]);
+ newchunk.size = fetch_32bits(&buffer[4]);
/* if we are a list, fetch the list type */
- if (newchunk->type == CHUNKTYPE_LIST || newchunk->type == CHUNKTYPE_RIFF)
+ if (newchunk.type == CHUNKTYPE_LIST || newchunk.type == CHUNKTYPE_RIFF)
{
- filerr = osd_read(file->file, &buffer[8], newchunk->offset + 8, 4, &bytesread);
- if (filerr != FILERR_NONE || bytesread != 4)
- return AVIERR_INVALID_DATA;
- newchunk->listtype = fetch_32bits(&buffer[8]);
+ filerr = m_file->read(&buffer[8], newchunk.offset + 8, 4, bytesread);
+ if (filerr != osd_file::error::NONE || bytesread != 4)
+ return error::INVALID_DATA;
+ newchunk.listtype = fetch_32bits(&buffer[8]);
}
- return AVIERR_NONE;
+ return error::NONE;
}
@@ -1836,98 +2208,95 @@ static avi_error get_next_chunk_internal(avi_file *file, const avi_chunk *parent
* @return The movie data.
*/
-static avi_error read_movie_data(avi_file *file)
+avi_file::error avi_file_impl::read_movie_data()
{
avi_chunk riff, hdrl, avih, strl, strh, strf, indx, movi, idx1;
- avi_error avierr;
- int strindex;
+ error avierr;
/* find the RIFF chunk */
- avierr = find_first_chunk(file, CHUNKTYPE_RIFF, nullptr, &riff);
- if (avierr != AVIERR_NONE)
- goto error;
+ avierr = find_first_chunk(CHUNKTYPE_RIFF, nullptr, riff);
+ if (avierr != error::NONE)
+ return avierr;
/* verify that the RIFF type is AVI */
if (riff.listtype != LISTTYPE_AVI)
{
- avierr = AVIERR_INVALID_DATA;
- goto error;
+ avierr = error::INVALID_DATA;
+ return avierr;
}
/* find the hdrl LIST chunk within the RIFF */
- avierr = find_first_list(file, LISTTYPE_HDRL, &riff, &hdrl);
- if (avierr != AVIERR_NONE)
- goto error;
+ avierr = find_first_list(LISTTYPE_HDRL, &riff, hdrl);
+ if (avierr != error::NONE)
+ return avierr;
/* find the avih chunk */
- avierr = find_first_chunk(file, CHUNKTYPE_AVIH, &hdrl, &avih);
- if (avierr != AVIERR_NONE)
- goto error;
+ avierr = find_first_chunk(CHUNKTYPE_AVIH, &hdrl, avih);
+ if (avierr != error::NONE)
+ return avierr;
/* parse the avih chunk */
- avierr = parse_avih_chunk(file, &avih);
- if (avierr != AVIERR_NONE)
- goto error;
+ avierr = parse_avih_chunk(avih);
+ if (avierr != error::NONE)
+ return avierr;
/* loop over strl LIST chunks */
- strindex = 0;
- for (avierr = find_first_list(file, LISTTYPE_STRL, &hdrl, &strl); avierr == AVIERR_NONE; avierr = find_next_list(file, LISTTYPE_STRL, &hdrl, &strl))
+ int strindex = 0;
+ for (avierr = find_first_list(LISTTYPE_STRL, &hdrl, strl); avierr == error::NONE; avierr = find_next_list(LISTTYPE_STRL, &hdrl, strl))
{
/* if we have too many, it's a bad file */
- if (strindex >= file->streams)
- goto error;
+ if (strindex >= m_streams.size())
+ return avierr;
/* find the strh chunk */
- avierr = find_first_chunk(file, CHUNKTYPE_STRH, &strl, &strh);
- if (avierr != AVIERR_NONE)
- goto error;
+ avierr = find_first_chunk(CHUNKTYPE_STRH, &strl, strh);
+ if (avierr != error::NONE)
+ return avierr;
/* parse the data */
- avierr = parse_strh_chunk(file, &file->stream[strindex], &strh);
- if (avierr != AVIERR_NONE)
- goto error;
+ avierr = parse_strh_chunk(m_streams[strindex], strh);
+ if (avierr != error::NONE)
+ return avierr;
/* find the strf chunk */
- avierr = find_first_chunk(file, CHUNKTYPE_STRF, &strl, &strf);
- if (avierr != AVIERR_NONE)
- goto error;
+ avierr = find_first_chunk(CHUNKTYPE_STRF, &strl, strf);
+ if (avierr != error::NONE)
+ return avierr;
/* parse the data */
- avierr = parse_strf_chunk(file, &file->stream[strindex], &strf);
- if (avierr != AVIERR_NONE)
- goto error;
+ avierr = parse_strf_chunk(m_streams[strindex], strf);
+ if (avierr != error::NONE)
+ return avierr;
/* find the indx chunk, if present */
- avierr = find_first_chunk(file, CHUNKTYPE_INDX, &strl, &indx);
- if (avierr == AVIERR_NONE)
- avierr = parse_indx_chunk(file, &file->stream[strindex], &indx);
+ avierr = find_first_chunk(CHUNKTYPE_INDX, &strl, indx);
+ if (avierr == error::NONE)
+ avierr = parse_indx_chunk(m_streams[strindex], indx);
/* next stream */
strindex++;
}
/* normalize the error after parsing the stream headers */
- if (avierr == AVIERR_END)
- avierr = AVIERR_NONE;
- if (avierr != AVIERR_NONE)
- goto error;
+ if (avierr == error::END)
+ avierr = error::NONE;
+ if (avierr != error::NONE)
+ return avierr;
/* find the base of the movi data */
- avierr = find_first_list(file, LISTTYPE_MOVI, &riff, &movi);
- if (avierr != AVIERR_NONE)
- goto error;
+ avierr = find_first_list(LISTTYPE_MOVI, &riff, movi);
+ if (avierr != error::NONE)
+ return avierr;
/* find and parse the idx1 chunk within the RIFF (if present) */
- avierr = find_first_chunk(file, CHUNKTYPE_IDX1, &riff, &idx1);
- if (avierr == AVIERR_NONE)
- avierr = parse_idx1_chunk(file, movi.offset + 8, &idx1);
- if (avierr != AVIERR_NONE)
- goto error;
+ avierr = find_first_chunk(CHUNKTYPE_IDX1, &riff, idx1);
+ if (avierr == error::NONE)
+ avierr = parse_idx1_chunk(movi.offset + 8, idx1);
+ if (avierr != error::NONE)
+ return avierr;
/* now extract the movie info */
- avierr = extract_movie_info(file);
-
-error:
+ avierr = extract_movie_info();
return avierr;
}
@@ -1947,59 +2316,55 @@ error:
* @return The extracted movie information.
*/
-static avi_error extract_movie_info(avi_file *file)
+avi_file::error avi_file_impl::extract_movie_info()
{
- //avi_stream *audiostream;
avi_stream *stream;
+ int offset;
/* get the video stream */
- stream = get_video_stream(file);
+ stream = get_video_stream();
if (stream != nullptr)
{
/* fill in the info */
- file->info.video_format = stream->format;
- file->info.video_timescale = stream->rate;
- file->info.video_sampletime = stream->scale;
- file->info.video_numsamples = stream->samples;
- file->info.video_width = stream->width;
- file->info.video_height = stream->height;
+ m_info.video_format = stream->format();
+ m_info.video_timescale = stream->rate();
+ m_info.video_sampletime = stream->scale();
+ m_info.video_numsamples = stream->samples();
+ m_info.video_width = stream->width();
+ m_info.video_height = stream->height();
}
/* get the first audio stream */
- stream = get_audio_stream(file, 0, nullptr);
+ stream = get_audio_stream(0, offset);
if (stream != nullptr)
{
/* fill in the info */
- file->info.audio_format = stream->format;
- file->info.audio_timescale = stream->rate;
- file->info.audio_sampletime = stream->scale;
- file->info.audio_numsamples = stream->samples;
- file->info.audio_channels = 1;
- file->info.audio_samplebits = stream->samplebits;
- file->info.audio_samplerate = stream->samplerate;
+ m_info.audio_format = stream->format();
+ m_info.audio_timescale = stream->rate();
+ m_info.audio_sampletime = stream->scale();
+ m_info.audio_numsamples = stream->samples();
+ m_info.audio_channels = 1;
+ m_info.audio_samplebits = stream->samplebits();
+ m_info.audio_samplerate = stream->samplerate();
}
/* now make sure all other audio streams are valid */
- //audiostream = stream;
- while (1)
+ while (nullptr != (stream = get_audio_stream(m_info.audio_channels, offset)))
{
/* get the stream info */
- stream = get_audio_stream(file, file->info.audio_channels, nullptr);
- if (stream == nullptr)
- break;
- file->info.audio_channels++;
+ m_info.audio_channels++;
/* verify compatibility */
- if (file->info.audio_format != stream->format ||
- file->info.audio_timescale != stream->rate ||
- file->info.audio_sampletime != stream->scale ||
- file->info.audio_numsamples != stream->samples ||
- file->info.audio_samplebits != stream->samplebits ||
- file->info.audio_samplerate != stream->samplerate)
- return AVIERR_INCOMPATIBLE_AUDIO_STREAMS;
+ if (m_info.audio_format != stream->format() ||
+ m_info.audio_timescale != stream->rate() ||
+ m_info.audio_sampletime != stream->scale() ||
+ m_info.audio_numsamples != stream->samples() ||
+ m_info.audio_samplebits != stream->samplebits() ||
+ m_info.audio_samplerate != stream->samplerate())
+ return error::INCOMPATIBLE_AUDIO_STREAMS;
}
- return AVIERR_NONE;
+ return error::NONE;
}
@@ -2019,28 +2384,21 @@ static avi_error extract_movie_info(avi_file *file)
* @return An avi_error.
*/
-static avi_error parse_avih_chunk(avi_file *file, avi_chunk *avih)
+avi_file::error avi_file_impl::parse_avih_chunk(avi_chunk const &avih)
{
- UINT8 *chunkdata = nullptr;
- avi_error avierr;
-
/* read the data */
- avierr = read_chunk_data(file, avih, &chunkdata);
- if (avierr != AVIERR_NONE)
- goto error;
+ std::unique_ptr<std::uint8_t []> chunkdata;
+ error avierr = read_chunk_data(avih, chunkdata);
+ if (avierr != error::NONE)
+ return avierr;
/* extract the data */
- file->streams = fetch_32bits(&chunkdata[24]);
+ std::uint32_t const streams = fetch_32bits(&chunkdata[24]);
/* allocate memory for the streams */
- file->stream = (avi_stream *)malloc(sizeof(*file->stream) * file->streams);
- if (file->stream == nullptr)
- goto error;
- memset(file->stream, 0, sizeof(*file->stream) * file->streams);
+ m_streams.clear();
+ m_streams.resize(streams);
-error:
- if (chunkdata != nullptr)
- free(chunkdata);
return avierr;
}
@@ -2062,26 +2420,16 @@ error:
* @return An avi_error.
*/
-static avi_error parse_strh_chunk(avi_file *file, avi_stream *stream, avi_chunk *strh)
+avi_file::error avi_file_impl::parse_strh_chunk(avi_stream &stream, avi_chunk const &strh)
{
- UINT8 *chunkdata = nullptr;
- avi_error avierr;
-
/* read the data */
- avierr = read_chunk_data(file, strh, &chunkdata);
- if (avierr != AVIERR_NONE)
- goto error;
+ std::unique_ptr<std::uint8_t []> chunkdata;
+ error const avierr = read_chunk_data(strh, chunkdata);
+ if (avierr != error::NONE)
+ return avierr;
/* extract the data */
- stream->type = fetch_32bits(&chunkdata[0]);
- stream->scale = fetch_32bits(&chunkdata[20]);
- stream->rate = fetch_32bits(&chunkdata[24]);
- stream->samples = fetch_32bits(&chunkdata[32]);
-
-error:
- if (chunkdata != nullptr)
- free(chunkdata);
- return avierr;
+ return stream.set_strh_data(&chunkdata[0], strh.size);
}
@@ -2102,43 +2450,17 @@ error:
* @return An avi_error.
*/
-static avi_error parse_strf_chunk(avi_file *file, avi_stream *stream, avi_chunk *strf)
+avi_file::error avi_file_impl::parse_strf_chunk(avi_stream &stream, avi_chunk const &strf)
{
- UINT8 *chunkdata = nullptr;
- avi_error avierr;
+ error avierr;
/* read the data */
- avierr = read_chunk_data(file, strf, &chunkdata);
- if (avierr != AVIERR_NONE)
- goto error;
-
- /* audio and video streams have differing headers */
- if (stream->type == STREAMTYPE_VIDS)
- {
- stream->width = fetch_32bits(&chunkdata[4]);
- stream->height = fetch_32bits(&chunkdata[8]);
- stream->depth = fetch_16bits(&chunkdata[14]);
- stream->format = fetch_32bits(&chunkdata[16]);
-
- /* extra extraction for HuffYUV data */
- if (stream->format == FORMAT_HFYU && strf->size >= 56)
- {
- avierr = huffyuv_extract_tables(stream, chunkdata, strf->size);
- if (avierr != AVIERR_NONE)
- goto error;
- }
- }
- else if (stream->type == STREAMTYPE_AUDS)
- {
- stream->channels = fetch_16bits(&chunkdata[2]);
- stream->samplebits = fetch_16bits(&chunkdata[14]);
- stream->samplerate = fetch_32bits(&chunkdata[4]);
- }
+ std::unique_ptr<std::uint8_t []> chunkdata;
+ avierr = read_chunk_data(strf, chunkdata);
+ if (avierr != error::NONE)
+ return avierr;
-error:
- if (chunkdata != nullptr)
- free(chunkdata);
- return avierr;
+ return stream.set_strf_data(&chunkdata[0], strf.size);
}
@@ -2158,50 +2480,46 @@ error:
* @return An avi_error.
*/
-static avi_error parse_indx_chunk(avi_file *file, avi_stream *stream, avi_chunk *strf)
+avi_file::error avi_file_impl::parse_indx_chunk(avi_stream &stream, avi_chunk const &strf)
{
- UINT32 entries, entry;
- UINT8 *chunkdata = nullptr;
- UINT16 longs_per_entry;
- UINT8 type;
- UINT64 baseoffset;
- avi_error avierr;
+ error avierr;
/* read the data */
- avierr = read_chunk_data(file, strf, &chunkdata);
- if (avierr != AVIERR_NONE)
- goto error;
+ std::unique_ptr<std::uint8_t []> chunkdata;
+ avierr = read_chunk_data(strf, chunkdata);
+ if (avierr != error::NONE)
+ return avierr;
/* extract the data */
- longs_per_entry = fetch_16bits(&chunkdata[0]);
+ std::uint16_t const longs_per_entry = fetch_16bits(&chunkdata[0]);
//subtype = chunkdata[2];
- type = chunkdata[3];
- entries = fetch_32bits(&chunkdata[4]);
+ std::uint8_t const type = chunkdata[3];
+ std::uint32_t const entries = fetch_32bits(&chunkdata[4]);
//id = fetch_32bits(&chunkdata[8]);
- baseoffset = fetch_64bits(&chunkdata[12]);
+ std::uint64_t const baseoffset = fetch_64bits(&chunkdata[12]);
/* if this is a superindex, loop over entries and call ourselves recursively */
if (type == AVI_INDEX_OF_INDEXES)
{
/* validate the size of each entry */
if (longs_per_entry != 4)
- return AVIERR_INVALID_DATA;
+ return error::INVALID_DATA;
/* loop over entries and create subchunks for each */
- for (entry = 0; entry < entries; entry++)
+ for (std::uint32_t entry = 0; entry < entries; entry++)
{
- const UINT8 *base = &chunkdata[24 + entry * 16];
- file_error filerr;
+ const std::uint8_t *base = &chunkdata[24 + entry * 16];
+ osd_file::error filerr;
avi_chunk subchunk;
- UINT32 bytes_read;
- UINT8 buffer[8];
+ std::uint32_t bytes_read;
+ std::uint8_t buffer[8];
/* go read the subchunk */
subchunk.offset = fetch_64bits(&base[0]);
- filerr = osd_read(file->file, buffer, subchunk.offset, sizeof(buffer), &bytes_read);
- if (filerr != FILERR_NONE || bytes_read != sizeof(buffer))
+ filerr = m_file->read(buffer, subchunk.offset, sizeof(buffer), bytes_read);
+ if (filerr != osd_file::error::NONE || bytes_read != sizeof(buffer))
{
- avierr = AVIERR_READ_ERROR;
+ avierr = error::READ_ERROR;
break;
}
@@ -2210,8 +2528,8 @@ static avi_error parse_indx_chunk(avi_file *file, avi_stream *stream, avi_chunk
subchunk.size = fetch_32bits(&buffer[4]);
/* recursively parse each referenced chunk; stop if we hit an error */
- avierr = parse_indx_chunk(file, stream, &subchunk);
- if (avierr != AVIERR_NONE)
+ avierr = parse_indx_chunk(stream, subchunk);
+ if (avierr != error::NONE)
break;
}
}
@@ -2221,25 +2539,22 @@ static avi_error parse_indx_chunk(avi_file *file, avi_stream *stream, avi_chunk
{
/* validate the size of each entry */
if (longs_per_entry != 2 && longs_per_entry != 3)
- return AVIERR_INVALID_DATA;
+ return error::INVALID_DATA;
/* loop over entries and parse out the data */
- for (entry = 0; entry < entries; entry++)
+ for (std::uint32_t entry = 0; entry < entries; entry++)
{
- const UINT8 *base = &chunkdata[24 + entry * 4 * longs_per_entry];
- UINT32 offset = fetch_32bits(&base[0]);
- UINT32 size = fetch_32bits(&base[4]) & 0x7fffffff; // bit 31 == NOT a keyframe
+ const std::uint8_t *base = &chunkdata[24 + entry * 4 * longs_per_entry];
+ std::uint32_t offset = fetch_32bits(&base[0]);
+ std::uint32_t size = fetch_32bits(&base[4]) & 0x7fffffff; // bit 31 == NOT a keyframe
/* set the info for this chunk and advance */
- avierr = set_stream_chunk_info(stream, stream->chunks++, baseoffset + offset - 8, size + 8);
- if (avierr != AVIERR_NONE)
+ avierr = stream.set_chunk_info(stream.chunks(), baseoffset + offset - 8, size + 8);
+ if (avierr != error::NONE)
break;
}
}
-error:
- if (chunkdata != nullptr)
- free(chunkdata);
return avierr;
}
@@ -2249,7 +2564,7 @@ error:
-------------------------------------------------*/
/**
- * @fn static avi_error parse_idx1_chunk(avi_file *file, UINT64 baseoffset, avi_chunk *idx1)
+ * @fn static avi_error parse_idx1_chunk(avi_file *file, std::uint64_t baseoffset, avi_chunk *idx1)
*
* @brief Parse index 1 chunk.
*
@@ -2260,48 +2575,39 @@ error:
* @return An avi_error.
*/
-static avi_error parse_idx1_chunk(avi_file *file, UINT64 baseoffset, avi_chunk *idx1)
+avi_file::error avi_file_impl::parse_idx1_chunk(std::uint64_t baseoffset, avi_chunk const &idx1)
{
- UINT8 *chunkdata = nullptr;
- avi_error avierr;
- UINT32 entries;
- UINT32 entry;
+ error avierr;
/* read the data */
- avierr = read_chunk_data(file, idx1, &chunkdata);
- if (avierr != AVIERR_NONE)
- goto error;
+ std::unique_ptr<std::uint8_t []> chunkdata;
+ avierr = read_chunk_data(idx1, chunkdata);
+ if (avierr != error::NONE)
+ return avierr;
/* loop over entries */
- entries = idx1->size / 16;
- for (entry = 0; entry < entries; entry++)
+ std::uint32_t const entries = idx1.size / 16;
+ for (std::uint32_t entry = 0; entry < entries; entry++)
{
- const UINT8 *base = &chunkdata[entry * 16];
- UINT32 chunkid = fetch_32bits(&base[0]);
- UINT32 offset = fetch_32bits(&base[8]);
- UINT32 size = fetch_32bits(&base[12]);
- avi_stream *stream;
+ std::uint8_t const *const base = &chunkdata[entry * 16];
+ std::uint32_t const chunkid = fetch_32bits(&base[0]);
+ std::uint32_t const offset = fetch_32bits(&base[8]);
+ std::uint32_t const size = fetch_32bits(&base[12]);
int streamnum;
/* determine the stream index */
streamnum = ((chunkid >> 8) & 0xff) - '0';
streamnum += 10 * ((chunkid & 0xff) - '0');
- if (streamnum >= file->streams)
- {
- avierr = AVIERR_INVALID_DATA;
- goto error;
- }
- stream = &file->stream[streamnum];
+ if (streamnum >= m_streams.size())
+ return error::INVALID_DATA;
+ avi_stream &stream = m_streams[streamnum];
/* set the appropriate entry */
- avierr = set_stream_chunk_info(stream, stream->chunks++, baseoffset + offset, size + 8);
- if (avierr != AVIERR_NONE)
- goto error;
+ avierr = stream.set_chunk_info(stream.chunks(), baseoffset + offset, size + 8);
+ if (avierr != error::NONE)
+ return avierr;
}
-error:
- if (chunkdata != nullptr)
- free(chunkdata);
return avierr;
}
@@ -2311,7 +2617,7 @@ error:
-------------------------------------------------*/
/**
- * @fn static avi_error chunk_open(avi_file *file, UINT32 type, UINT32 listtype, UINT32 estlength)
+ * @fn static avi_error chunk_open(avi_file *file, std::uint32_t type, std::uint32_t listtype, std::uint32_t estlength)
*
* @brief Queries if a given chunk open.
*
@@ -2323,57 +2629,55 @@ error:
* @return An avi_error.
*/
-static avi_error chunk_open(avi_file *file, UINT32 type, UINT32 listtype, UINT32 estlength)
+avi_file::error avi_file_impl::chunk_open(std::uint32_t type, std::uint32_t listtype, std::uint32_t estlength)
{
- file_error filerr;
- avi_chunk *chunk;
- UINT32 written;
-
/* if we're out of stack entries, bail */
- if (file->chunksp >= ARRAY_LENGTH(file->chunkstack))
- return AVIERR_STACK_TOO_DEEP;
- chunk = &file->chunkstack[file->chunksp++];
+ if (m_chunksp >= m_chunkstack.size())
+ return error::STACK_TOO_DEEP;
+ avi_chunk &chunk = m_chunkstack[m_chunksp++];
/* set up the chunk information */
- chunk->offset = file->writeoffs;
- chunk->size = estlength;
- chunk->type = type;
- chunk->listtype = listtype;
+ chunk.offset = m_writeoffs;
+ chunk.size = estlength;
+ chunk.type = type;
+ chunk.listtype = listtype;
/* non-list types */
if (type != CHUNKTYPE_RIFF && type != CHUNKTYPE_LIST)
{
- UINT8 buffer[8];
+ std::uint8_t buffer[8];
/* populate the header */
- put_32bits(&buffer[0], chunk->type);
- put_32bits(&buffer[4], chunk->size);
+ put_32bits(&buffer[0], chunk.type);
+ put_32bits(&buffer[4], chunk.size);
/* write the header */
- filerr = osd_write(file->file, buffer, file->writeoffs, sizeof(buffer), &written);
- if (filerr != FILERR_NONE || written != sizeof(buffer))
- return AVIERR_WRITE_ERROR;
- file->writeoffs += written;
+ std::uint32_t written;
+ osd_file::error const filerr = m_file->write(buffer, m_writeoffs, sizeof(buffer), written);
+ if (filerr != osd_file::error::NONE || written != sizeof(buffer))
+ return error::WRITE_ERROR;
+ m_writeoffs += written;
}
/* list types */
else
{
- UINT8 buffer[12];
+ std::uint8_t buffer[12];
/* populate the header */
- put_32bits(&buffer[0], chunk->type);
- put_32bits(&buffer[4], chunk->size);
- put_32bits(&buffer[8], chunk->listtype);
+ put_32bits(&buffer[0], chunk.type);
+ put_32bits(&buffer[4], chunk.size);
+ put_32bits(&buffer[8], chunk.listtype);
/* write the header */
- filerr = osd_write(file->file, buffer, file->writeoffs, sizeof(buffer), &written);
- if (filerr != FILERR_NONE || written != sizeof(buffer))
- return AVIERR_WRITE_ERROR;
- file->writeoffs += written;
+ std::uint32_t written;
+ osd_file::error const filerr = m_file->write(buffer, m_writeoffs, sizeof(buffer), written);
+ if (filerr != osd_file::error::NONE || written != sizeof(buffer))
+ return error::WRITE_ERROR;
+ m_writeoffs += written;
}
- return AVIERR_NONE;
+ return error::NONE;
}
@@ -2391,32 +2695,31 @@ static avi_error chunk_open(avi_file *file, UINT32 type, UINT32 listtype, UINT32
* @return An avi_error.
*/
-static avi_error chunk_close(avi_file *file)
+avi_file::error avi_file_impl::chunk_close()
{
- avi_chunk *chunk = &file->chunkstack[--file->chunksp];
- UINT64 chunksize = file->writeoffs - (chunk->offset + 8);
- UINT32 written;
+ avi_chunk const &chunk = m_chunkstack[--m_chunksp];
+ std::uint64_t const chunksize = m_writeoffs - (chunk.offset + 8);
/* error if we don't fit into 32 bits */
- if (chunksize != (UINT32)chunksize)
- return AVIERR_INVALID_DATA;
+ if (chunksize != std::uint32_t(chunksize))
+ return error::INVALID_DATA;
/* write the final size if it is different from the guess */
- if (chunk->size != chunksize)
+ if (chunk.size != chunksize)
{
- file_error filerr;
- UINT8 buffer[4];
+ std::uint8_t buffer[4];
- put_32bits(&buffer[0], (UINT32)chunksize);
- filerr = osd_write(file->file, buffer, chunk->offset + 4, sizeof(buffer), &written);
- if (filerr != FILERR_NONE || written != sizeof(buffer))
- return AVIERR_WRITE_ERROR;
+ put_32bits(&buffer[0], std::uint32_t(chunksize));
+ std::uint32_t written;
+ osd_file::error const filerr = m_file->write(buffer, chunk.offset + 4, sizeof(buffer), written);
+ if (filerr != osd_file::error::NONE || written != sizeof(buffer))
+ return error::WRITE_ERROR;
}
/* round up to the next word */
- file->writeoffs += chunksize & 1;
+ m_writeoffs += chunksize & 1;
- return AVIERR_NONE;
+ return error::NONE;
}
@@ -2425,7 +2728,7 @@ static avi_error chunk_close(avi_file *file)
-------------------------------------------------*/
/**
- * @fn static avi_error chunk_write(avi_file *file, UINT32 type, const void *data, UINT32 length)
+ * @fn static avi_error chunk_write(avi_file *file, std::uint32_t type, const void *data, std::uint32_t length)
*
* @brief Chunk write.
*
@@ -2437,67 +2740,63 @@ static avi_error chunk_close(avi_file *file)
* @return An avi_error.
*/
-static avi_error chunk_write(avi_file *file, UINT32 type, const void *data, UINT32 length)
+avi_file::error avi_file_impl::chunk_write(std::uint32_t type, const void *data, std::uint32_t length)
{
- file_error filerr;
- avi_error avierr;
- UINT32 idxreserve;
- UINT32 written;
+ error avierr;
/* if we are the first RIFF, we must reserve enough space for the IDX chunk */
- idxreserve = 0;
- if (file->riffbase == 0 && type != CHUNKTYPE_IDX1)
- idxreserve = compute_idx1_size(file);
+ std::uint32_t const idxreserve = (m_riffbase == 0 && type != CHUNKTYPE_IDX1) ? compute_idx1_size() : 0;
/* if we are getting too big, split the RIFF */
/* note that we ignore writes before the current RIFF base, as those are assumed to be
overwrites of a chunk from the previous RIFF */
- if (file->writeoffs >= file->riffbase && file->writeoffs + length + idxreserve - file->riffbase >= MAX_RIFF_SIZE)
+ if ((m_writeoffs >= m_riffbase) && ((m_writeoffs + length + idxreserve - m_riffbase) >= MAX_RIFF_SIZE))
{
/* close the movi list */
- avierr = chunk_close(file);
- if (avierr != AVIERR_NONE)
+ avierr = chunk_close();
+ if (avierr != error::NONE)
return avierr;
/* write the idx1 chunk if this is the first */
- if (file->riffbase == 0)
+ if (m_riffbase == 0)
{
- avierr = write_idx1_chunk(file);
- if (avierr != AVIERR_NONE)
+ avierr = write_idx1_chunk();
+ if (avierr != error::NONE)
return avierr;
}
/* close the RIFF */
- avierr = chunk_close(file);
- if (avierr != AVIERR_NONE)
+ avierr = chunk_close();
+ if (avierr != error::NONE)
return avierr;
/* open a new RIFF */
- file->riffbase = file->writeoffs;
- avierr = chunk_open(file, CHUNKTYPE_RIFF, LISTTYPE_AVIX, 0);
- if (avierr != AVIERR_NONE)
+ m_riffbase = m_writeoffs;
+ avierr = chunk_open(CHUNKTYPE_RIFF, LISTTYPE_AVIX, 0);
+ if (avierr != error::NONE)
return avierr;
/* open a nested movi list */
- file->saved_movi_offset = file->writeoffs;
- avierr = chunk_open(file, CHUNKTYPE_LIST, LISTTYPE_MOVI, 0);
- if (avierr != AVIERR_NONE)
+ m_saved_movi_offset = m_writeoffs;
+ avierr = chunk_open(CHUNKTYPE_LIST, LISTTYPE_MOVI, 0);
+ if (avierr != error::NONE)
return avierr;
}
/* open the chunk */
- avierr = chunk_open(file, type, 0, length);
- if (avierr != AVIERR_NONE)
+ avierr = chunk_open(type, 0, length);
+ if (avierr != error::NONE)
return avierr;
/* write the data */
- filerr = osd_write(file->file, data, file->writeoffs, length, &written);
- if (filerr != FILERR_NONE || written != length)
- return AVIERR_WRITE_ERROR;
- file->writeoffs += written;
+ std::uint32_t written;
+ osd_file::error const filerr = m_file->write(data, m_writeoffs, length, written);
+ if (filerr != osd_file::error::NONE || written != length)
+ return error::WRITE_ERROR;
+ m_writeoffs += written;
/* close the chunk */
- return chunk_close(file);
+ return chunk_close();
}
@@ -2509,7 +2808,7 @@ static avi_error chunk_write(avi_file *file, UINT32 type, const void *data, UINT
-------------------------------------------------*/
/**
- * @fn static avi_error chunk_overwrite(avi_file *file, UINT32 type, const void *data, UINT32 length, UINT64 *offset, int initial_write)
+ * @fn static avi_error chunk_overwrite(avi_file *file, std::uint32_t type, const void *data, std::uint32_t length, std::uint64_t *offset, int initial_write)
*
* @brief Chunk overwrite.
*
@@ -2523,28 +2822,27 @@ static avi_error chunk_write(avi_file *file, UINT32 type, const void *data, UINT
* @return An avi_error.
*/
-static avi_error chunk_overwrite(avi_file *file, UINT32 type, const void *data, UINT32 length, UINT64 *offset, int initial_write)
+avi_file::error avi_file_impl::chunk_overwrite(std::uint32_t type, const void *data, std::uint32_t length, std::uint64_t &offset, bool initial_write)
{
- UINT64 savedoffset = 0;
- avi_error avierr;
+ std::uint64_t savedoffset = 0;
/* if this is our initial write, save the offset */
if (initial_write)
- *offset = file->writeoffs;
+ offset = m_writeoffs;
/* otherwise, remember the current write offset and replace it with the original */
else
{
- savedoffset = file->writeoffs;
- file->writeoffs = *offset;
+ savedoffset = m_writeoffs;
+ m_writeoffs = offset;
}
/* write the chunk */
- avierr = chunk_write(file, type, data, length);
+ error const avierr = chunk_write(type, data, length);
/* if this isn't the initial write, restore the previous offset */
if (!initial_write)
- file->writeoffs = savedoffset;
+ m_writeoffs = savedoffset;
return avierr;
}
@@ -2565,67 +2863,66 @@ static avi_error chunk_overwrite(avi_file *file, UINT32 type, const void *data,
* @return An avi_error.
*/
-static avi_error write_initial_headers(avi_file *file)
+avi_file::error avi_file_impl::write_initial_headers()
{
- avi_error avierr;
- int strnum;
+ error avierr;
/* reset the write pointer */
- file->writeoffs = 0;
+ m_writeoffs = 0;
/* open a RIFF chunk */
- avierr = chunk_open(file, CHUNKTYPE_RIFF, LISTTYPE_AVI, 0);
- if (avierr != AVIERR_NONE)
+ avierr = chunk_open(CHUNKTYPE_RIFF, LISTTYPE_AVI, 0);
+ if (avierr != error::NONE)
return avierr;
/* open a hdlr LIST */
- avierr = chunk_open(file, CHUNKTYPE_LIST, LISTTYPE_HDRL, 0);
- if (avierr != AVIERR_NONE)
+ avierr = chunk_open(CHUNKTYPE_LIST, LISTTYPE_HDRL, 0);
+ if (avierr != error::NONE)
return avierr;
/* write an avih chunk */
- avierr = write_avih_chunk(file, TRUE);
- if (avierr != AVIERR_NONE)
+ avierr = write_avih_chunk(true);
+ if (avierr != error::NONE)
return avierr;
/* for each stream, write a strl LIST */
- for (strnum = 0; strnum < file->streams; strnum++)
+ for (int strnum = 0; strnum < m_streams.size(); strnum++)
{
/* open a strl LIST */
- avierr = chunk_open(file, CHUNKTYPE_LIST, LISTTYPE_STRL, 0);
- if (avierr != AVIERR_NONE)
+ avierr = chunk_open(CHUNKTYPE_LIST, LISTTYPE_STRL, 0);
+ if (avierr != error::NONE)
return avierr;
/* write the strh chunk */
- avierr = write_strh_chunk(file, &file->stream[strnum], TRUE);
- if (avierr != AVIERR_NONE)
+ avierr = write_strh_chunk(m_streams[strnum], true);
+ if (avierr != error::NONE)
return avierr;
/* write the strf chunk */
- avierr = write_strf_chunk(file, &file->stream[strnum]);
- if (avierr != AVIERR_NONE)
+ avierr = write_strf_chunk(m_streams[strnum]);
+ if (avierr != error::NONE)
return avierr;
/* write the indx chunk */
- avierr = write_indx_chunk(file, &file->stream[strnum], TRUE);
- if (avierr != AVIERR_NONE)
+ avierr = write_indx_chunk(m_streams[strnum], true);
+ if (avierr != error::NONE)
return avierr;
/* close the strl LIST */
- avierr = chunk_close(file);
- if (avierr != AVIERR_NONE)
+ avierr = chunk_close();
+ if (avierr != error::NONE)
return avierr;
}
/* close the hdlr LIST */
- avierr = chunk_close(file);
- if (avierr != AVIERR_NONE)
+ avierr = chunk_close();
+ if (avierr != error::NONE)
return avierr;
/* open a movi LIST */
- file->saved_movi_offset = file->writeoffs;
- avierr = chunk_open(file, CHUNKTYPE_LIST, LISTTYPE_MOVI, 0);
- if (avierr != AVIERR_NONE)
+ m_saved_movi_offset = m_writeoffs;
+ avierr = chunk_open(CHUNKTYPE_LIST, LISTTYPE_MOVI, 0);
+ if (avierr != error::NONE)
return avierr;
return avierr;
@@ -2648,23 +2945,23 @@ static avi_error write_initial_headers(avi_file *file)
* @return An avi_error.
*/
-static avi_error write_avih_chunk(avi_file *file, int initial_write)
+avi_file::error avi_file_impl::write_avih_chunk(bool initial_write)
{
- avi_stream *video = get_video_stream(file);
- UINT8 buffer[56];
+ avi_stream *video = get_video_stream();
+ std::uint8_t buffer[56];
/* reset the buffer */
- memset(buffer, 0, sizeof(buffer));
+ std::memset(buffer, 0, sizeof(buffer));
- put_32bits(&buffer[0], 1000000 * (INT64)video->scale / video->rate); /* dwMicroSecPerFrame */
+ put_32bits(&buffer[0], 1000000 * std::int64_t(video->scale()) / video->rate()); /* dwMicroSecPerFrame */
put_32bits(&buffer[12], AVIF_HASINDEX | AVIF_ISINTERLEAVED); /* dwFlags */
- put_32bits(&buffer[16], video->samples); /* dwTotalFrames */
- put_32bits(&buffer[24], file->streams); /* dwStreams */
- put_32bits(&buffer[32], video->width); /* dwWidth */
- put_32bits(&buffer[36], video->height); /* dwHeight */
+ put_32bits(&buffer[16], video->samples()); /* dwTotalFrames */
+ put_32bits(&buffer[24], m_streams.size()); /* dwStreams */
+ put_32bits(&buffer[32], video->width()); /* dwWidth */
+ put_32bits(&buffer[36], video->height()); /* dwHeight */
/* (over)write the chunk */
- return chunk_overwrite(file, CHUNKTYPE_AVIH, buffer, sizeof(buffer), &file->saved_avih_offset, initial_write);
+ return chunk_overwrite(CHUNKTYPE_AVIH, buffer, sizeof(buffer), m_saved_avih_offset, initial_write);
}
@@ -2685,41 +2982,41 @@ static avi_error write_avih_chunk(avi_file *file, int initial_write)
* @return An avi_error.
*/
-static avi_error write_strh_chunk(avi_file *file, avi_stream *stream, int initial_write)
+avi_file::error avi_file_impl::write_strh_chunk(avi_stream &stream, bool initial_write)
{
- UINT8 buffer[56];
+ std::uint8_t buffer[56];
/* reset the buffer */
- memset(buffer, 0, sizeof(buffer));
+ std::memset(buffer, 0, sizeof(buffer));
- put_32bits(&buffer[0], stream->type); /* fccType */
- put_32bits(&buffer[20], stream->scale); /* dwScale */
- put_32bits(&buffer[24], stream->rate); /* dwRate */
- put_32bits(&buffer[32], stream->samples); /* dwLength */
+ put_32bits(&buffer[0], stream.type()); /* fccType */
+ put_32bits(&buffer[20], stream.scale()); /* dwScale */
+ put_32bits(&buffer[24], stream.rate()); /* dwRate */
+ put_32bits(&buffer[32], stream.samples()); /* dwLength */
put_32bits(&buffer[40], 10000); /* dwQuality */
/* video-stream specific data */
- if (stream->type == STREAMTYPE_VIDS)
+ if (stream.type() == STREAMTYPE_VIDS)
{
put_32bits(&buffer[4], /* fccHandler */
- (stream->format == FORMAT_HFYU) ? HANDLER_HFYU : HANDLER_DIB);
+ (stream.format() == FORMAT_HFYU) ? HANDLER_HFYU : HANDLER_DIB);
put_32bits(&buffer[36], /* dwSuggestedBufferSize */
- stream->width * stream->height * 4);
- put_16bits(&buffer[52], stream->width); /* rcFrame.right */
- put_16bits(&buffer[54], stream->height); /* rcFrame.bottom */
+ stream.width() * stream.height() * 4);
+ put_16bits(&buffer[52], stream.width()); /* rcFrame.right */
+ put_16bits(&buffer[54], stream.height()); /* rcFrame.bottom */
}
/* audio-stream specific data */
- if (stream->type == STREAMTYPE_AUDS)
+ if (stream.type() == STREAMTYPE_AUDS)
{
put_32bits(&buffer[36], /* dwSuggestedBufferSize */
- stream->samplerate * stream->channels * (stream->samplebits / 8));
+ stream.samplerate() * stream.bytes_per_sample());
put_32bits(&buffer[44], /* dwSampleSize */
- stream->channels * (stream->samplebits / 8));
+ stream.bytes_per_sample());
}
/* write the chunk */
- return chunk_overwrite(file, CHUNKTYPE_STRH, buffer, sizeof(buffer), &stream->saved_strh_offset, initial_write);
+ return chunk_overwrite(CHUNKTYPE_STRH, buffer, sizeof(buffer), stream.saved_strh_offset(), initial_write);
}
@@ -2739,51 +3036,51 @@ static avi_error write_strh_chunk(avi_file *file, avi_stream *stream, int initia
* @return An avi_error.
*/
-static avi_error write_strf_chunk(avi_file *file, avi_stream *stream)
+avi_file::error avi_file_impl::write_strf_chunk(avi_stream const &stream)
{
/* video stream */
- if (stream->type == STREAMTYPE_VIDS)
+ if (stream.type() == STREAMTYPE_VIDS)
{
- UINT8 buffer[40];
+ std::uint8_t buffer[40];
/* reset the buffer */
- memset(buffer, 0, sizeof(buffer));
+ std::memset(buffer, 0, sizeof(buffer));
put_32bits(&buffer[0], sizeof(buffer)); /* biSize */
- put_32bits(&buffer[4], stream->width); /* biWidth */
- put_32bits(&buffer[8], stream->height); /* biHeight */
+ put_32bits(&buffer[4], stream.width()); /* biWidth */
+ put_32bits(&buffer[8], stream.height()); /* biHeight */
put_16bits(&buffer[12], 1); /* biPlanes */
- put_16bits(&buffer[14], stream->depth); /* biBitCount */
- put_32bits(&buffer[16], stream->format); /* biCompression */
+ put_16bits(&buffer[14], stream.depth()); /* biBitCount */
+ put_32bits(&buffer[16], stream.format()); /* biCompression */
put_32bits(&buffer[20], /* biSizeImage */
- stream->width * stream->height * (stream->depth + 7) / 8);
+ stream.width() * stream.height() * (stream.depth() + 7) / 8);
/* write the chunk */
- return chunk_write(file, CHUNKTYPE_STRF, buffer, sizeof(buffer));
+ return chunk_write(CHUNKTYPE_STRF, buffer, sizeof(buffer));
}
/* audio stream */
- if (stream->type == STREAMTYPE_AUDS)
+ if (stream.type() == STREAMTYPE_AUDS)
{
- UINT8 buffer[16];
+ std::uint8_t buffer[16];
/* reset the buffer */
- memset(buffer, 0, sizeof(buffer));
+ std::memset(buffer, 0, sizeof(buffer));
put_16bits(&buffer[0], 1); /* wFormatTag */
- put_16bits(&buffer[2], stream->channels); /* nChannels */
- put_32bits(&buffer[4], stream->samplerate); /* nSamplesPerSec */
+ put_16bits(&buffer[2], stream.channels()); /* nChannels */
+ put_32bits(&buffer[4], stream.samplerate()); /* nSamplesPerSec */
put_32bits(&buffer[8], /* nAvgBytesPerSec */
- stream->samplerate * stream->channels * (stream->samplebits / 8));
+ stream.samplerate() * stream.bytes_per_sample());
put_16bits(&buffer[12], /* nBlockAlign */
- stream->channels * (stream->samplebits / 8));
- put_16bits(&buffer[14], stream->samplebits); /* wBitsPerSample */
+ stream.bytes_per_sample());
+ put_16bits(&buffer[14], stream.samplebits()); /* wBitsPerSample */
/* write the chunk */
- return chunk_write(file, CHUNKTYPE_STRF, buffer, sizeof(buffer));
+ return chunk_write(CHUNKTYPE_STRF, buffer, sizeof(buffer));
}
- return AVIERR_INVALID_DATA;
+ return error::INVALID_DATA;
}
@@ -2804,35 +3101,30 @@ static avi_error write_strf_chunk(avi_file *file, avi_stream *stream)
* @return An avi_error.
*/
-static avi_error write_indx_chunk(avi_file *file, avi_stream *stream, int initial_write)
+avi_file::error avi_file_impl::write_indx_chunk(avi_stream &stream, bool initial_write)
{
- UINT8 buffer[24 + 16 * MAX_AVI_SIZE_IN_GB / 4];
- UINT32 chunkid, indexchunkid;
- UINT32 master_entries = 0;
+ std::uint8_t buffer[24 + 16 * MAX_AVI_SIZE_IN_GB / 4];
+ std::uint32_t master_entries = 0;
/* reset the buffer */
- memset(buffer, 0, sizeof(buffer));
+ std::memset(buffer, 0, sizeof(buffer));
/* construct the chunk ID and index chunk ID */
- chunkid = get_chunkid_for_stream(file, stream);
- indexchunkid = AVI_FOURCC('i', 'x', '0' + (stream - file->stream) / 10, '0' + (stream - file->stream) % 10);
+ std::uint32_t const chunkid = get_chunkid_for_stream(&stream);
+ std::uint32_t const indexchunkid = AVI_FOURCC('i', 'x', '0' + (&stream - &m_streams[0]) / 10, '0' + (&stream - &m_streams[0]) % 10);
/* loop over chunks of 4GB and write out indexes for them first */
- if (!initial_write && file->riffbase != 0)
+ if (!initial_write && m_riffbase != 0)
{
- UINT64 currentbase;
- for (currentbase = 0; currentbase < file->writeoffs; currentbase += FOUR_GB)
+ for (std::uint64_t currentbase = 0; currentbase < m_writeoffs; currentbase += FOUR_GB)
{
- UINT64 currentend = currentbase + FOUR_GB;
- UINT32 chunks_this_index = 0;
- UINT32 bytes_this_index = 0;
- avi_error avierr;
- UINT32 chunknum;
- UINT8 *tempbuf;
+ std::uint64_t const currentend = currentbase + FOUR_GB;
+ std::uint32_t chunks_this_index = 0;
+ std::uint32_t bytes_this_index = 0;
/* count chunks that are in this region */
- for (chunknum = 0; chunknum < stream->chunks; chunknum++)
- if (stream->chunk[chunknum].offset >= currentbase && stream->chunk[chunknum].offset < currentend)
+ for (std::uint32_t chunknum = 0; chunknum < stream.chunks(); chunknum++)
+ if (stream.chunk(chunknum).offset >= currentbase && stream.chunk(chunknum).offset < currentend)
chunks_this_index++;
/* if no chunks, skip */
@@ -2840,10 +3132,10 @@ static avi_error write_indx_chunk(avi_file *file, avi_stream *stream, int initia
continue;
/* allocate memory */
- tempbuf = (UINT8 *)malloc(24 + 8 * chunks_this_index);
- if (tempbuf == nullptr)
- return AVIERR_NO_MEMORY;
- memset(tempbuf, 0, 24 + 8 * chunks_this_index);
+ std::unique_ptr<std::uint8_t []> tempbuf;
+ try { tempbuf.reset(new std::uint8_t[24 + 8 * chunks_this_index]); }
+ catch (...) { return error::NO_MEMORY; }
+ std::memset(&tempbuf[0], 0, 24 + 8 * chunks_this_index);
/* make a regular index */
put_16bits(&tempbuf[0], 2); /* wLongsPerEntry */
@@ -2855,28 +3147,27 @@ static avi_error write_indx_chunk(avi_file *file, avi_stream *stream, int initia
/* now fill in the indexes */
chunks_this_index = 0;
- for (chunknum = 0; chunknum < stream->chunks; chunknum++)
- if (stream->chunk[chunknum].offset >= currentbase && stream->chunk[chunknum].offset < currentend)
+ for (std::uint32_t chunknum = 0; chunknum < stream.chunks(); chunknum++)
+ if (stream.chunk(chunknum).offset >= currentbase && stream.chunk(chunknum).offset < currentend)
{
- put_32bits(&tempbuf[24 + 8 * chunks_this_index + 0], stream->chunk[chunknum].offset + 8 - currentbase);
- put_32bits(&tempbuf[24 + 8 * chunks_this_index + 4], stream->chunk[chunknum].length - 8);
- bytes_this_index += stream->chunk[chunknum].length;
+ put_32bits(&tempbuf[24 + 8 * chunks_this_index + 0], stream.chunk(chunknum).offset + 8 - currentbase);
+ put_32bits(&tempbuf[24 + 8 * chunks_this_index + 4], stream.chunk(chunknum).length - 8);
+ bytes_this_index += stream.chunk(chunknum).length;
chunks_this_index++;
}
/* write the offset of this index to the master table */
- put_64bits(&buffer[24 + 16 * master_entries + 0], file->writeoffs);
+ put_64bits(&buffer[24 + 16 * master_entries + 0], m_writeoffs);
put_32bits(&buffer[24 + 16 * master_entries + 8], 24 + 8 * chunks_this_index + 8);
- if (stream->type == STREAMTYPE_VIDS)
+ if (stream.type() == STREAMTYPE_VIDS)
put_32bits(&buffer[24 + 16 * master_entries + 12], chunks_this_index);
- else if (stream->type == STREAMTYPE_AUDS)
- put_32bits(&buffer[24 + 16 * master_entries + 12], bytes_this_index / ((stream->samplebits / 8) * stream->channels));
+ else if (stream.type() == STREAMTYPE_AUDS)
+ put_32bits(&buffer[24 + 16 * master_entries + 12], bytes_this_index / stream.bytes_per_sample());
master_entries++;
/* write the index */
- avierr = chunk_write(file, indexchunkid, tempbuf, 24 + 8 * chunks_this_index);
- free(tempbuf);
- if (avierr != AVIERR_NONE)
+ error const avierr = chunk_write(indexchunkid, &tempbuf[0], 24 + 8 * chunks_this_index);
+ if (avierr != error::NONE)
return avierr;
}
}
@@ -2892,7 +3183,7 @@ static avi_error write_indx_chunk(avi_file *file, avi_stream *stream, int initia
}
/* (over)write the chunk */
- return chunk_overwrite(file, (master_entries == 0) ? CHUNKTYPE_JUNK : CHUNKTYPE_INDX, buffer, sizeof(buffer), &stream->saved_indx_offset, initial_write);
+ return chunk_overwrite((master_entries == 0) ? CHUNKTYPE_JUNK : CHUNKTYPE_INDX, buffer, sizeof(buffer), stream.saved_indx_offset(), initial_write);
}
@@ -2910,47 +3201,42 @@ static avi_error write_indx_chunk(avi_file *file, avi_stream *stream, int initia
* @return An avi_error.
*/
-static avi_error write_idx1_chunk(avi_file *file)
+avi_file::error avi_file_impl::write_idx1_chunk()
{
- UINT32 tempbuflength = compute_idx1_size(file) - 8;
- UINT32 curchunk[2] = { 0 };
- UINT32 curoffset;
- avi_error avierr;
- UINT8 *tempbuf;
+ std::uint32_t const tempbuflength = compute_idx1_size() - 8;
+ std::uint32_t curchunk[2] = { 0 };
/* allocate a temporary buffer */
- tempbuf = (UINT8 *)malloc(tempbuflength);
- if (tempbuf == nullptr)
- return AVIERR_NO_MEMORY;
+ std::unique_ptr<std::uint8_t []> tempbuf;
+ try { tempbuf.reset(new std::uint8_t[tempbuflength]); }
+ catch (...) { return error::NO_MEMORY; }
/* fill it in */
- for (curoffset = 0; curoffset < tempbuflength; curoffset += 16)
+ for (std::uint32_t curoffset = 0; curoffset < tempbuflength; curoffset += 16)
{
- UINT64 minoffset = ~(UINT64)0;
- int strnum, minstr = 0;
+ std::uint64_t minoffset = ~std::uint64_t(0);
+ int minstr = 0;
/* determine which stream has the next chunk */
- for (strnum = 0; strnum < file->streams; strnum++)
- if (curchunk[strnum] < file->stream[strnum].chunks && file->stream[strnum].chunk[curchunk[strnum]].offset < minoffset)
+ for (int strnum = 0; strnum < m_streams.size(); strnum++)
+ if (curchunk[strnum] < m_streams[strnum].chunks() && m_streams[strnum].chunk(curchunk[strnum]).offset < minoffset)
{
- minoffset = file->stream[strnum].chunk[curchunk[strnum]].offset;
+ minoffset = m_streams[strnum].chunk(curchunk[strnum]).offset;
minstr = strnum;
}
/* make an entry for this index */
- put_32bits(&tempbuf[curoffset + 0], get_chunkid_for_stream(file, &file->stream[minstr]));
+ put_32bits(&tempbuf[curoffset + 0], get_chunkid_for_stream(&m_streams[minstr]));
put_32bits(&tempbuf[curoffset + 4], 0x0010 /* AVIIF_KEYFRAME */);
- put_32bits(&tempbuf[curoffset + 8], minoffset - (file->saved_movi_offset + 8));
- put_32bits(&tempbuf[curoffset + 12], file->stream[minstr].chunk[curchunk[minstr]].length - 8);
+ put_32bits(&tempbuf[curoffset + 8], minoffset - (m_saved_movi_offset + 8));
+ put_32bits(&tempbuf[curoffset + 12], m_streams[minstr].chunk(curchunk[minstr]).length - 8);
/* advance the chunk counter for this stream */
curchunk[minstr]++;
}
/* write the chunk */
- avierr = chunk_write(file, CHUNKTYPE_IDX1, tempbuf, tempbuflength);
- free(tempbuf);
- return avierr;
+ return chunk_write(CHUNKTYPE_IDX1, &tempbuf[0], tempbuflength);
}
@@ -2969,31 +3255,31 @@ static avi_error write_idx1_chunk(avi_file *file)
* @return An avi_error.
*/
-static avi_error soundbuf_initialize(avi_file *file)
+avi_file::error avi_file_impl::soundbuf_initialize()
{
- avi_stream *audio = get_audio_stream(file, 0, nullptr);
- avi_stream *video = get_video_stream(file);
+ int offset;
+ avi_stream *const audio = get_audio_stream(0, offset);
+ avi_stream *const video = get_video_stream();
/* we require a video stream */
if (video == nullptr)
- return AVIERR_UNSUPPORTED_VIDEO_FORMAT;
+ return error::UNSUPPORTED_VIDEO_FORMAT;
/* skip if no audio stream */
if (audio == nullptr)
- return AVIERR_NONE;
+ return error::NONE;
/* determine the number of samples we want in our buffer; 2 seconds should be enough */
- file->soundbuf_samples = file->info.audio_samplerate * SOUND_BUFFER_MSEC / 1000;
+ m_soundbuf_samples = m_info.audio_samplerate * SOUND_BUFFER_MSEC / 1000;
/* allocate a buffer */
- file->soundbuf = (INT16 *)malloc(file->soundbuf_samples * file->info.audio_channels * sizeof(file->soundbuf[0]));
- if (file->soundbuf == nullptr)
- return AVIERR_NO_MEMORY;
- memset(file->soundbuf, 0, file->soundbuf_samples * file->info.audio_channels * sizeof(file->soundbuf[0]));
+ m_soundbuf.clear();
+ try { m_soundbuf.resize(m_soundbuf_samples * m_info.audio_channels, 0); }
+ catch (...) { return error::NO_MEMORY; }
/* determine the number of frames to be ahead (0.75secs) */
- file->soundbuf_frames = ((UINT64)video->rate * 75) / ((UINT64)video->scale * 100) + 1;
- return AVIERR_NONE;
+ m_soundbuf_frames = (std::uint64_t(video->rate()) * 75) / (std::uint64_t(video->scale()) * 100) + 1;
+ return error::NONE;
}
@@ -3003,7 +3289,7 @@ static avi_error soundbuf_initialize(avi_file *file)
-------------------------------------------------*/
/**
- * @fn static avi_error soundbuf_write_chunk(avi_file *file, UINT32 framenum)
+ * @fn static avi_error soundbuf_write_chunk(avi_file *file, std::uint32_t framenum)
*
* @brief Soundbuf write chunk.
*
@@ -3013,30 +3299,30 @@ static avi_error soundbuf_initialize(avi_file *file)
* @return An avi_error.
*/
-static avi_error soundbuf_write_chunk(avi_file *file, UINT32 framenum)
+avi_file::error avi_file_impl::soundbuf_write_chunk(std::uint32_t framenum)
{
- avi_stream *stream = get_audio_stream(file, 0, nullptr);
- avi_error avierr;
- UINT32 length;
+ int offset;
+ avi_stream *const stream = get_audio_stream(0, offset);
+ std::uint32_t length;
/* skip if no audio stream */
if (stream == nullptr)
- return AVIERR_NONE;
+ return error::NONE;
/* determine the length of this chunk */
if (framenum == 0)
- length = framenum_to_samplenum(file, file->soundbuf_frames);
+ length = framenum_to_samplenum(m_soundbuf_frames);
else
- length = framenum_to_samplenum(file, framenum + 1 + file->soundbuf_frames) - framenum_to_samplenum(file, framenum + file->soundbuf_frames);
- length *= stream->channels * sizeof(INT16);
+ length = framenum_to_samplenum(framenum + 1 + m_soundbuf_frames) - framenum_to_samplenum(framenum + m_soundbuf_frames);
+ length *= stream->channels() * sizeof(std::int16_t);
/* then do the initial write */
- avierr = chunk_write(file, get_chunkid_for_stream(file, stream), file->soundbuf, length);
- if (avierr != AVIERR_NONE)
+ error const avierr = chunk_write(get_chunkid_for_stream(stream), &m_soundbuf[0], length);
+ if (avierr != error::NONE)
return avierr;
/* set the info for this new chunk */
- return set_stream_chunk_info(stream, stream->chunks, file->writeoffs - length - 8, length + 8);
+ return stream->set_chunk_info(stream->chunks(), m_writeoffs - length - 8, length + 8);
}
@@ -3056,36 +3342,35 @@ static avi_error soundbuf_write_chunk(avi_file *file, UINT32 framenum)
* @return An avi_error.
*/
-static avi_error soundbuf_flush(avi_file *file, int only_flush_full)
+avi_file::error avi_file_impl::soundbuf_flush(bool only_flush_full)
{
- avi_stream *stream = get_audio_stream(file, 0, nullptr);
- INT32 channelsamples = file->soundbuf_samples;
- INT32 processedsamples = 0;
- UINT32 bytes_per_sample;
- UINT32 finalchunks;
- avi_error avierr;
- UINT32 chunknum;
- UINT32 chunkid;
- int channel;
+ int offset;
+ avi_stream *const stream = get_audio_stream(0, offset);
+ std::int32_t channelsamples = m_soundbuf_samples;
+ std::int32_t processedsamples = 0;
+ std::uint32_t finalchunks;
+ error avierr;
+ std::uint32_t chunknum;
+ std::uint32_t chunkid;
/* skip if no stream */
if (stream == nullptr)
- return AVIERR_NONE;
+ return error::NONE;
/* get the chunk ID for this stream */
- chunkid = get_chunkid_for_stream(file, stream);
- bytes_per_sample = stream->channels * sizeof(INT16);
- finalchunks = stream->chunks;
+ chunkid = get_chunkid_for_stream(stream);
+ std::uint32_t const bytes_per_sample = stream->channels() * sizeof(std::int16_t);
+ finalchunks = stream->chunks();
/* find out how many samples we've accumulated */
- for (channel = 0; channel < stream->channels; channel++)
- channelsamples = MIN(channelsamples, file->soundbuf_chansamples[channel]);
+ for (int channel = 0; channel < stream->channels(); channel++)
+ channelsamples = (std::min<std::int32_t>)(channelsamples, m_soundbuf_chansamples[channel]);
/* loop over pending sound chunks */
- for (chunknum = file->soundbuf_chunks; chunknum < stream->chunks; chunknum++)
+ for (chunknum = m_soundbuf_chunks; chunknum < stream->chunks(); chunknum++)
{
- avi_chunk_list *chunk = &stream->chunk[chunknum];
- UINT32 chunksamples = (chunk->length - 8) / bytes_per_sample;
+ avi_chunk_list &chunk = stream->chunk(chunknum);
+ std::uint32_t const chunksamples = (chunk.length - 8) / bytes_per_sample;
/* stop if we don't have enough to satisfy this chunk */
if (only_flush_full && channelsamples < chunksamples)
@@ -3094,696 +3379,300 @@ static avi_error soundbuf_flush(avi_file *file, int only_flush_full)
/* if we don't have all the samples we need, pad with 0's */
if (channelsamples > 0 && channelsamples < chunksamples)
{
- if (processedsamples + chunksamples > file->soundbuf_samples)
- return AVIERR_EXCEEDED_SOUND_BUFFER;
- memset(&file->soundbuf[(processedsamples + channelsamples) * stream->channels], 0, (chunksamples - channelsamples) * bytes_per_sample);
+ if (processedsamples + chunksamples > m_soundbuf_samples)
+ return error::EXCEEDED_SOUND_BUFFER;
+ std::memset(&m_soundbuf[(processedsamples + channelsamples) * stream->channels()], 0, (chunksamples - channelsamples) * bytes_per_sample);
}
/* if we're completely out of samples, clear the buffer entirely and use the end */
else if (channelsamples <= 0)
{
- processedsamples = file->soundbuf_samples - chunksamples;
- memset(&file->soundbuf[processedsamples * stream->channels], 0, chunksamples * bytes_per_sample);
+ processedsamples = m_soundbuf_samples - chunksamples;
+ std::memset(&m_soundbuf[processedsamples * stream->channels()], 0, chunksamples * bytes_per_sample);
chunkid = CHUNKTYPE_JUNK;
finalchunks--;
}
/* copy the sample data in */
- avierr = chunk_overwrite(file, chunkid, &file->soundbuf[processedsamples * stream->channels], chunk->length - 8, &chunk->offset, FALSE);
- if (avierr != AVIERR_NONE)
+ avierr = chunk_overwrite(chunkid, &m_soundbuf[processedsamples * stream->channels()], chunk.length - 8, chunk.offset, false);
+ if (avierr != error::NONE)
return avierr;
/* add up the samples */
if (channelsamples > chunksamples)
- file->info.audio_numsamples = stream->samples += chunksamples;
+ m_info.audio_numsamples = stream->add_samples(chunksamples);
else if (channelsamples > 0)
- file->info.audio_numsamples = stream->samples += channelsamples;
+ m_info.audio_numsamples = stream->add_samples(channelsamples);
/* advance past those */
processedsamples += chunksamples;
channelsamples -= chunksamples;
- channelsamples = MAX(0, channelsamples);
+ channelsamples = (std::max)(0, channelsamples);
}
/* if we have a non-zero offset, shift everything down */
if (processedsamples > 0)
{
/* first account for the samples we processed */
- memmove(&file->soundbuf[0], &file->soundbuf[processedsamples * stream->channels], (file->soundbuf_samples - processedsamples) * bytes_per_sample);
- for (channel = 0; channel < stream->channels; channel++)
- file->soundbuf_chansamples[channel] -= processedsamples;
+ std::memmove(&m_soundbuf[0], &m_soundbuf[processedsamples * stream->channels()], (m_soundbuf_samples - processedsamples) * bytes_per_sample);
+ for (int channel = 0; channel < stream->channels(); channel++)
+ m_soundbuf_chansamples[channel] -= processedsamples;
}
/* update the final chunk count */
if (!only_flush_full)
- stream->chunks = finalchunks;
+ stream->set_chunks(finalchunks);
/* account for flushed chunks */
- file->soundbuf_chunks = chunknum;
- return AVIERR_NONE;
+ m_soundbuf_chunks = chunknum;
+ return error::NONE;
}
/*-------------------------------------------------
- rgb32_compress_to_rgb - "compress" an RGB32
- bitmap to an RGB encoded frame
+ printf_chunk_recursive - print information
+ about a chunk recursively
-------------------------------------------------*/
/**
- * @fn static avi_error rgb32_compress_to_rgb(avi_stream *stream, const bitmap_rgb32 &bitmap, UINT8 *data, UINT32 numbytes)
- *
- * @brief RGB 32 compress to RGB.
+ * @fn static void printf_chunk_recursive(avi_file *file, avi_chunk *container, int indent)
*
- * @param [in,out] stream If non-null, the stream.
- * @param bitmap The bitmap.
- * @param [in,out] data If non-null, the data.
- * @param numbytes The numbytes.
+ * @brief Printf chunk recursive.
*
- * @return An avi_error.
+ * @param [in,out] file If non-null, the file.
+ * @param [in,out] container If non-null, the container.
+ * @param indent The indent.
*/
-static avi_error rgb32_compress_to_rgb(avi_stream *stream, const bitmap_rgb32 &bitmap, UINT8 *data, UINT32 numbytes)
+void avi_file_impl::printf_chunk_recursive(avi_chunk const *container, int indent)
{
- int height = MIN(stream->height, bitmap.height());
- int width = MIN(stream->width, bitmap.width());
- UINT8 *dataend = data + numbytes;
- int x, y;
+ char size[20], offset[20];
+ avi_chunk curchunk;
+ error avierr;
- /* compressed video */
- for (y = 0; y < height; y++)
+ /* iterate over chunks in this container */
+ for (avierr = get_first_chunk(container, curchunk); avierr == error::NONE; avierr = get_next_chunk(container, curchunk))
{
- const UINT32 *source = &bitmap.pix32(y);
- UINT8 *dest = data + (stream->height - 1 - y) * stream->width * 3;
-
- for (x = 0; x < width && dest < dataend; x++)
- {
- rgb_t pix = *source++;
- *dest++ = pix.b();
- *dest++ = pix.g();
- *dest++ = pix.r();
- }
+ std::uint32_t chunksize = curchunk.size;
+ bool recurse = false;
- /* fill in any blank space on the right */
- for ( ; x < stream->width && dest < dataend; x++)
- {
- *dest++ = 0;
- *dest++ = 0;
- *dest++ = 0;
- }
- }
+ u64toa(curchunk.size, size);
+ u64toa(curchunk.offset, offset);
+ printf("%*schunk = %c%c%c%c, size=%s (%s)\n", indent, "",
+ std::uint8_t(curchunk.type >> 0),
+ std::uint8_t(curchunk.type >> 8),
+ std::uint8_t(curchunk.type >> 16),
+ std::uint8_t(curchunk.type >> 24),
+ size, offset);
- /* fill in any blank space on the bottom */
- for ( ; y < stream->height; y++)
- {
- UINT8 *dest = data + (stream->height - 1 - y) * stream->width * 3;
- for (x = 0; x < stream->width && dest < dataend; x++)
+ /* certain chunks are just containers; recurse into them */
+ switch (curchunk.type)
{
- *dest++ = 0;
- *dest++ = 0;
- *dest++ = 0;
+ /* basic containers */
+ case CHUNKTYPE_RIFF:
+ case CHUNKTYPE_LIST:
+ printf("%*stype = %c%c%c%c\n", indent, "",
+ std::uint8_t(curchunk.listtype >> 0),
+ std::uint8_t(curchunk.listtype >> 8),
+ std::uint8_t(curchunk.listtype >> 16),
+ std::uint8_t(curchunk.listtype >> 24));
+ recurse = true;
+ chunksize = 0;
+ break;
}
- }
-
- return AVIERR_NONE;
-}
-
-
-/*-------------------------------------------------
- yuv_decompress_to_yuy16 - decompress a YUV
- encoded frame to a YUY16 bitmap
--------------------------------------------------*/
-
-/**
- * @fn static avi_error yuv_decompress_to_yuy16(avi_stream *stream, const UINT8 *data, UINT32 numbytes, bitmap_yuy16 &bitmap)
- *
- * @brief Yuv decompress to yuy 16.
- *
- * @param [in,out] stream If non-null, the stream.
- * @param data The data.
- * @param numbytes The numbytes.
- * @param [in,out] bitmap The bitmap.
- *
- * @return An avi_error.
- */
-static avi_error yuv_decompress_to_yuy16(avi_stream *stream, const UINT8 *data, UINT32 numbytes, bitmap_yuy16 &bitmap)
-{
- const UINT16 *dataend = (const UINT16 *)(data + numbytes);
- int x, y;
-
- /* compressed video */
- for (y = 0; y < stream->height; y++)
- {
- const UINT16 *source = (const UINT16 *)data + y * stream->width;
- UINT16 *dest = &bitmap.pix16(y);
-
- /* switch off the compression */
- switch (stream->format)
+ /* print data within the chunk */
+ if (chunksize > 0 && curchunk.size < 1024 * 1024)
{
- case FORMAT_UYVY:
- for (x = 0; x < stream->width && source < dataend; x++)
- *dest++ = *source++;
- break;
+ std::unique_ptr<std::uint8_t []> data;
- case FORMAT_VYUY:
- case FORMAT_YUY2:
- for (x = 0; x < stream->width && source < dataend; x++)
+ /* read the data for a chunk */
+ avierr = read_chunk_data(curchunk, data);
+ if (avierr == error::NONE)
+ {
+ std::uint32_t const bytes = (std::min)(std::uint32_t(512), chunksize);
+ for (std::uint32_t i = 0; i < bytes; i++)
{
- UINT16 pix = *source++;
- *dest++ = (pix >> 8) | (pix << 8);
+ if (i % 16 == 0) printf("%*s ", indent, "");
+ printf("%02X ", data[i]);
+ if (i % 16 == 15) printf("\n");
}
- break;
+ if (chunksize % 16 != 0) printf("\n");
+ }
}
+
+ /* if we're recursing, dive down */
+ if (recurse)
+ printf_chunk_recursive(&curchunk, indent + 4);
}
- return AVIERR_NONE;
+ /* if we didn't get a legitimate error, indicate that */
+ if (avierr != error::END)
+ printf("[chunk error %d]\n", int(avierr));
}
+} // anonymous namespace
+
+
+
+/***************************************************************************
+ IMPLEMENTATION
+***************************************************************************/
/*-------------------------------------------------
- yuy16_compress_to_yuy - "compress" a YUY16
- bitmap to a YUV encoded frame
+ avi_open - open an AVI movie file for read
-------------------------------------------------*/
/**
- * @fn static avi_error yuy16_compress_to_yuy(avi_stream *stream, const bitmap_yuy16 &bitmap, UINT8 *data, UINT32 numbytes)
+ * @fn avi_error avi_open(const char *filename, avi_file **file)
*
- * @brief Yuy 16 compress to yuy.
+ * @brief Queries if a given avi open.
*
- * @param [in,out] stream If non-null, the stream.
- * @param bitmap The bitmap.
- * @param [in,out] data If non-null, the data.
- * @param numbytes The numbytes.
+ * @param filename Filename of the file.
+ * @param [in,out] file If non-null, the file.
*
* @return An avi_error.
*/
-static avi_error yuy16_compress_to_yuy(avi_stream *stream, const bitmap_yuy16 &bitmap, UINT8 *data, UINT32 numbytes)
+avi_file::error avi_file::open(std::string const &filename, ptr &file)
{
- const UINT16 *dataend = (const UINT16 *)(data + numbytes);
- int x, y;
-
- /* compressed video */
- for (y = 0; y < stream->height; y++)
- {
- const UINT16 *source = &bitmap.pix16(y);
- UINT16 *dest = (UINT16 *)data + y * stream->width;
+ /* open the file */
+ osd_file::ptr f;
+ std::uint64_t length;
+ if (osd_file::open(filename, OPEN_FLAG_READ, f, length) != osd_file::error::NONE)
+ return error::CANT_OPEN_FILE;
- /* switch off the compression */
- switch (stream->format)
- {
- case FORMAT_UYVY:
- for (x = 0; x < stream->width && dest < dataend; x++)
- *dest++ = *source++;
- break;
+ /* allocate the file */
+ std::unique_ptr<avi_file_impl> newfile;
+ try { newfile = std::make_unique<avi_file_impl>(std::move(f), length); }
+ catch (...) { return error::NO_MEMORY; }
- case FORMAT_VYUY:
- case FORMAT_YUY2:
- for (x = 0; x < stream->width && dest < dataend; x++)
- {
- UINT16 pix = *source++;
- *dest++ = (pix >> 8) | (pix << 8);
- }
- break;
- }
- }
+ /* parse the data */
+ error const avierr = newfile->read_movie_data();
+ if (avierr != error::NONE)
+ return avierr;
- return AVIERR_NONE;
+ file = std::move(newfile);
+ return error::NONE;
}
/*-------------------------------------------------
- huffyuv_extract_tables - extract HuffYUV
- tables
+ avi_create - create a new AVI movie file
-------------------------------------------------*/
/**
- * @fn static avi_error huffyuv_extract_tables(avi_stream *stream, const UINT8 *chunkdata, UINT32 size)
+ * @fn avi_error avi_create(const char *filename, const avi_movie_info *info, avi_file **file)
*
- * @brief Huffyuv extract tables.
+ * @brief Avi create.
*
- * @param [in,out] stream If non-null, the stream.
- * @param chunkdata The chunkdata.
- * @param size The size.
+ * @param filename Filename of the file.
+ * @param info The information.
+ * @param [in,out] file If non-null, the file.
*
* @return An avi_error.
*/
-static avi_error huffyuv_extract_tables(avi_stream *stream, const UINT8 *chunkdata, UINT32 size)
+avi_file::error avi_file::create(std::string const &filename, movie_info const &info, ptr &file)
{
- const UINT8 *chunkend = chunkdata + size;
- avi_error avierr = AVIERR_NONE;
- int tabnum;
-
- /* allocate memory for the data */
- stream->huffyuv = (huffyuv_data *)malloc(sizeof(*stream->huffyuv));
- if (stream->huffyuv == nullptr)
- {
- avierr = AVIERR_NO_MEMORY;
- goto error;
- }
-
- /* extract predictor information */
- if (&chunkdata[40] >= chunkend)
- return AVIERR_INVALID_DATA;
- stream->huffyuv->predictor = chunkdata[40];
+ /* validate video info */
+ if ((info.video_format != 0 && info.video_format != FORMAT_UYVY && info.video_format != FORMAT_VYUY && info.video_format != FORMAT_YUY2) ||
+ (info.video_width == 0) ||
+ (info.video_height == 0) ||
+ (info.video_depth == 0) ||
+ (info.video_depth % 8 != 0))
+ return error::UNSUPPORTED_VIDEO_FORMAT;
- /* make sure it's the left predictor */
- if ((stream->huffyuv->predictor & ~HUFFYUV_PREDICT_DECORR) != HUFFYUV_PREDICT_LEFT)
- return AVIERR_UNSUPPORTED_VIDEO_FORMAT;
+ /* validate audio info */
+ if (info.audio_format != 0 ||
+ info.audio_channels > MAX_SOUND_CHANNELS ||
+ info.audio_samplebits != 16)
+ return error::UNSUPPORTED_AUDIO_FORMAT;
- /* make sure it's 16bpp YUV data */
- if (chunkdata[41] != 16)
- return AVIERR_UNSUPPORTED_VIDEO_FORMAT;
- chunkdata += 44;
+ /* open the file */
+ osd_file::ptr f;
+ std::uint64_t length;
+ osd_file::error const filerr = osd_file::open(filename, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS, f, length);
+ if (filerr != osd_file::error::NONE)
+ return error::CANT_OPEN_FILE;
- /* loop over tables */
- for (tabnum = 0; tabnum < 3; tabnum++)
+ /* allocate the file */
+ error avierr;
+ std::unique_ptr<avi_file_impl> newfile;
+ try { newfile = std::make_unique<avi_file_impl>(std::move(f), info); }
+ catch (...)
{
- huffyuv_table *table = &stream->huffyuv->table[tabnum];
- UINT32 curbits, bitadd;
- UINT16 bitsat16 = 0;
- int offset = 0, bits;
-
- /* loop until we populate the whole table */
- while (offset < 256)
- {
- int data, shift, count, i;
-
- /* extract the next run */
- if (chunkdata >= chunkend)
- {
- avierr = AVIERR_INVALID_DATA;
- goto error;
- }
- data = *chunkdata++;
- shift = data & 0x1f;
- count = data >> 5;
-
- /* zero count means next whole byte is a count */
- if (count == 0)
- {
- if (chunkdata >= chunkend)
- {
- avierr = AVIERR_INVALID_DATA;
- goto error;
- }
- count = *chunkdata++;
- }
- for (i = 0; i < count; i++)
- table->shift[offset++] = shift;
- }
-
- /* now determine bit patterns and masks */
- curbits = 0;
- for (bits = 31; bits >= 0; bits--)
- {
- bitadd = 1 << (32 - bits);
-
- /* make sure we've cleared out all the bits below */
- if ((curbits & (bitadd - 1)) != 0)
- {
- avierr = AVIERR_INVALID_DATA;
- goto error;
- }
-
- /* find all entries with this shift count and assign them */
- for (offset = 0; offset < 256; offset++)
- if (table->shift[offset] == bits)
- {
- table->bits[offset] = curbits;
- table->mask[offset] = ~(bitadd - 1);
- curbits += bitadd;
- }
+ avierr = error::NO_MEMORY;
+ goto error;
+ }
- /* remember the bit pattern when we complete all the 17-bit codes */
- if (bits == 17)
- bitsat16 = curbits >> 16;
- }
+ /* initialize the sound buffering */
+ avierr = newfile->soundbuf_initialize();
+ if (avierr != error::NONE)
+ goto error;
- /* allocate the number of extra lookup tables we need */
- if (bitsat16 > 0)
- {
- table->extralookup = (UINT16 *)malloc(bitsat16 * 65536 * sizeof(table->extralookup[0]));
- if (table->extralookup == nullptr)
- {
- avierr = AVIERR_NO_MEMORY;
- goto error;
- }
- for (offset = 0; offset < bitsat16; offset++)
- table->baselookup[offset] = (offset << 8) | 0;
- }
+ /* write the initial headers */
+ avierr = newfile->write_initial_headers();
+ if (avierr != error::NONE)
+ goto error;
- /* then create lookup tables */
- for (offset = 0; offset < 256; offset++)
- if (table->shift[offset] > 16)
- {
- UINT16 *tablebase = table->extralookup + (table->bits[offset] >> 16) * 65536;
- UINT32 start = table->bits[offset] & 0xffff;
- UINT32 end = start + ((1 << (32 - table->shift[offset])) - 1);
- while (start <= end)
- tablebase[start++] = (offset << 8) | (table->shift[offset] - 16);
- }
- else if (table->shift[offset] > 0)
- {
- UINT32 start = table->bits[offset] >> 16;
- UINT32 end = start + ((1 << (16 - table->shift[offset])) - 1);
- while (start <= end)
- table->baselookup[start++] = (offset << 8) | table->shift[offset];
- }
- }
+ file = std::move(newfile);
+ return error::NONE;
error:
- if (avierr != AVIERR_NONE && stream->huffyuv != nullptr)
- {
- free(stream->huffyuv);
- stream->huffyuv = nullptr;
- }
+ f.reset();
+ newfile.reset();
+ osd_file::remove(filename);
return avierr;
}
/*-------------------------------------------------
- huffyuv_decompress_to_yuy16 - decompress a
- HuffYUV-encoded frame to a YUY16 bitmap
+ avi_error_string - get the error string for
+ an avi_error
-------------------------------------------------*/
/**
- * @fn static avi_error huffyuv_decompress_to_yuy16(avi_stream *stream, const UINT8 *data, UINT32 numbytes, bitmap_yuy16 &bitmap)
+ * @fn const char *avi_error_string(avi_error err)
*
- * @brief Huffyuv decompress to yuy 16.
+ * @brief Avi error string.
*
- * @param [in,out] stream If non-null, the stream.
- * @param data The data.
- * @param numbytes The numbytes.
- * @param [in,out] bitmap The bitmap.
+ * @param err The error.
*
- * @return An avi_error.
+ * @return null if it fails, else a char*.
*/
-static avi_error huffyuv_decompress_to_yuy16(avi_stream *stream, const UINT8 *data, UINT32 numbytes, bitmap_yuy16 &bitmap)
+const char *avi_file::error_string(error err)
{
- huffyuv_data *huffyuv = stream->huffyuv;
- int prevlines = (stream->height > 288) ? 2 : 1;
- UINT8 lastprevy = 0, lastprevcb = 0, lastprevcr = 0;
- UINT8 lasty = 0, lastcb = 0, lastcr = 0;
- UINT8 bitsinbuffer = 0;
- UINT32 bitbuffer = 0;
- UINT32 dataoffs = 0;
- int x, y;
-
- /* compressed video */
- for (y = 0; y < stream->height; y++)
- {
- UINT16 *dest = &bitmap.pix16(y);
-
- /* handle the first four bytes independently */
- x = 0;
- if (y == 0)
- {
- /* first DWORD is stored as YUY2 */
- lasty = data[dataoffs++];
- lastcb = data[dataoffs++];
- *dest++ = (lasty << 8) | lastcb;
- lasty = data[dataoffs++];
- lastcr = data[dataoffs++];
- *dest++ = (lasty << 8) | lastcr;
- x = 2;
- }
-
- /* loop over pixels */
- for ( ; x < stream->width; x++)
- {
- huffyuv_table *ytable = &huffyuv->table[0];
- huffyuv_table *ctable = &huffyuv->table[1 + (x & 1)];
- UINT16 pixel, huffdata;
- int shift;
-
- /* fill up the buffer; they store little-endian DWORDs, so we XOR with 3 */
- while (bitsinbuffer <= 24 && dataoffs < numbytes)
- {
- bitbuffer |= data[dataoffs++ ^ 3] << (24 - bitsinbuffer);
- bitsinbuffer += 8;
- }
-
- /* look up the Y component */
- huffdata = ytable->baselookup[bitbuffer >> 16];
- shift = huffdata & 0xff;
- if (shift == 0)
- {
- bitsinbuffer -= 16;
- bitbuffer <<= 16;
-
- /* fill up the buffer; they store little-endian DWORDs, so we XOR with 3 */
- while (bitsinbuffer <= 24 && dataoffs < numbytes)
- {
- bitbuffer |= data[dataoffs++ ^ 3] << (24 - bitsinbuffer);
- bitsinbuffer += 8;
- }
-
- huffdata = ytable->extralookup[(huffdata >> 8) * 65536 + (bitbuffer >> 16)];
- shift = huffdata & 0xff;
- }
- bitsinbuffer -= shift;
- bitbuffer <<= shift;
- pixel = huffdata & 0xff00;
-
- /* fill up the buffer; they store little-endian DWORDs, so we XOR with 3 */
- while (bitsinbuffer <= 24 && dataoffs < numbytes)
- {
- bitbuffer |= data[dataoffs++ ^ 3] << (24 - bitsinbuffer);
- bitsinbuffer += 8;
- }
-
- /* look up the Cb/Cr component */
- huffdata = ctable->baselookup[bitbuffer >> 16];
- shift = huffdata & 0xff;
- if (shift == 0)
- {
- bitsinbuffer -= 16;
- bitbuffer <<= 16;
-
- /* fill up the buffer; they store little-endian DWORDs, so we XOR with 3 */
- while (bitsinbuffer <= 24 && dataoffs < numbytes)
- {
- bitbuffer |= data[dataoffs++ ^ 3] << (24 - bitsinbuffer);
- bitsinbuffer += 8;
- }
-
- huffdata = ctable->extralookup[(huffdata >> 8) * 65536 + (bitbuffer >> 16)];
- shift = huffdata & 0xff;
- }
- bitsinbuffer -= shift;
- bitbuffer <<= shift;
- *dest++ = pixel | (huffdata >> 8);
- }
- }
-
- /* apply deltas */
- lastprevy = lastprevcb = lastprevcr = 0;
- for (y = 0; y < stream->height; y++)
+ switch (err)
{
- UINT16 *prevrow = &bitmap.pix16(y - prevlines);
- UINT16 *dest = &bitmap.pix16(y);
-
- /* handle the first four bytes independently */
- x = 0;
- if (y == 0)
- {
- /* lasty, lastcr, lastcb are set up previously */
- x = 2;
- }
-
- /* left predict or gradient predict */
- if ((huffyuv->predictor & ~HUFFYUV_PREDICT_DECORR) == HUFFYUV_PREDICT_LEFT ||
- ((huffyuv->predictor & ~HUFFYUV_PREDICT_DECORR) == HUFFYUV_PREDICT_GRADIENT))
- {
- /* first do left deltas */
- for ( ; x < stream->width; x += 2)
- {
- UINT16 pixel0 = dest[x + 0];
- UINT16 pixel1 = dest[x + 1];
-
- lasty += pixel0 >> 8;
- lastcb += pixel0;
- dest[x + 0] = (lasty << 8) | lastcb;
-
- lasty += pixel1 >> 8;
- lastcr += pixel1;
- dest[x + 1] = (lasty << 8) | lastcr;
- }
-
- /* for gradient, we then add in the previous row */
- if ((huffyuv->predictor & ~HUFFYUV_PREDICT_DECORR) == HUFFYUV_PREDICT_GRADIENT && y >= prevlines)
- for (x = 0; x < stream->width; x++)
- {
- UINT16 curpix = dest[x];
- UINT16 prevpix = prevrow[x];
- UINT8 ysum = (curpix >> 8) + (prevpix >> 8);
- UINT8 csum = curpix + prevpix;
- dest[x] = (ysum << 8) | csum;
- }
- }
-
- /* median predict on rows > 0 */
- else if ((huffyuv->predictor & ~HUFFYUV_PREDICT_DECORR) == HUFFYUV_PREDICT_MEDIAN && y >= prevlines)
- {
- for ( ; x < stream->width; x += 2)
- {
- UINT16 prevpixel0 = prevrow[x + 0];
- UINT16 prevpixel1 = prevrow[x + 1];
- UINT16 pixel0 = dest[x + 0];
- UINT16 pixel1 = dest[x + 1];
- UINT8 a, b, c;
-
- /* compute previous, above, and (prev + above - above-left) */
- a = lasty;
- b = prevpixel0 >> 8;
- c = lastprevy;
- lastprevy = b;
- if (a > b) { UINT8 tmp = a; a = b; b = tmp; }
- if (a > c) { UINT8 tmp = a; a = c; c = tmp; }
- if (b > c) { UINT8 tmp = b; b = c; c = tmp; }
- lasty = (pixel0 >> 8) + b;
-
- /* compute previous, above, and (prev + above - above-left) */
- a = lastcb;
- b = prevpixel0 & 0xff;
- c = lastprevcb;
- lastprevcb = b;
- if (a > b) { UINT8 tmp = a; a = b; b = tmp; }
- if (a > c) { UINT8 tmp = a; a = c; c = tmp; }
- if (b > c) { UINT8 tmp = b; b = c; c = tmp; }
- lastcb = (pixel0 & 0xff) + b;
- dest[x + 0] = (lasty << 8) | lastcb;
-
- /* compute previous, above, and (prev + above - above-left) */
- a = lasty;
- b = prevpixel1 >> 8;
- c = lastprevy;
- lastprevy = b;
- if (a > b) { UINT8 tmp = a; a = b; b = tmp; }
- if (a > c) { UINT8 tmp = a; a = c; c = tmp; }
- if (b > c) { UINT8 tmp = b; b = c; c = tmp; }
- lasty = (pixel1 >> 8) + b;
-
- /* compute previous, above, and (prev + above - above-left) */
- a = lastcr;
- b = prevpixel1 & 0xff;
- c = lastprevcr;
- lastprevcr = b;
- if (a > b) { UINT8 tmp = a; a = b; b = tmp; }
- if (a > c) { UINT8 tmp = a; a = c; c = tmp; }
- if (b > c) { UINT8 tmp = b; b = c; c = tmp; }
- lastcr = (pixel1 & 0xff) + b;
- dest[x + 1] = (lasty << 8) | lastcr;
- }
- }
+ case error::NONE: return "success";
+ case error::END: return "hit end of file";
+ case error::INVALID_DATA: return "invalid data";
+ case error::NO_MEMORY: return "out of memory";
+ case error::READ_ERROR: return "read error";
+ case error::WRITE_ERROR: return "write error";
+ case error::STACK_TOO_DEEP: return "stack overflow";
+ case error::UNSUPPORTED_FEATURE: return "unsupported feature";
+ case error::CANT_OPEN_FILE: return "unable to open file";
+ case error::INCOMPATIBLE_AUDIO_STREAMS: return "found incompatible audio streams";
+ case error::INVALID_SAMPLERATE: return "found invalid sample rate";
+ case error::INVALID_STREAM: return "invalid stream";
+ case error::INVALID_FRAME: return "invalid frame index";
+ case error::INVALID_BITMAP: return "invalid bitmap";
+ case error::UNSUPPORTED_VIDEO_FORMAT: return "unsupported video format";
+ case error::UNSUPPORTED_AUDIO_FORMAT: return "unsupported audio format";
+ case error::EXCEEDED_SOUND_BUFFER: return "sound buffer overflow";
+ default: return "undocumented error";
}
-
- return AVIERR_NONE;
}
-/**
- * @fn static void u64toa(UINT64 val, char *output)
- *
- * @brief 64toas.
- *
- * @param val The value.
- * @param [in,out] output If non-null, the output.
- */
-static void u64toa(UINT64 val, char *output)
+avi_file::avi_file()
{
- UINT32 lo = (UINT32)(val & 0xffffffff);
- UINT32 hi = (UINT32)(val >> 32);
- if (hi != 0)
- sprintf(output, "%X%08X", hi, lo);
- else
- sprintf(output, "%X", lo);
}
-/*-------------------------------------------------
- printf_chunk_recursive - print information
- about a chunk recursively
--------------------------------------------------*/
-
-/**
- * @fn static void printf_chunk_recursive(avi_file *file, avi_chunk *container, int indent)
- *
- * @brief Printf chunk recursive.
- *
- * @param [in,out] file If non-null, the file.
- * @param [in,out] container If non-null, the container.
- * @param indent The indent.
- */
-
-static void printf_chunk_recursive(avi_file *file, avi_chunk *container, int indent)
+avi_file::~avi_file()
{
- char size[20], offset[20];
- avi_chunk curchunk;
- int avierr;
-
- /* iterate over chunks in this container */
- for (avierr = get_first_chunk(file, container, &curchunk); avierr == AVIERR_NONE; avierr = get_next_chunk(file, container, &curchunk))
- {
- UINT32 chunksize = curchunk.size;
- int recurse = FALSE;
-
- u64toa(curchunk.size, size);
- u64toa(curchunk.offset, offset);
- printf("%*schunk = %c%c%c%c, size=%s (%s)\n", indent, "",
- (UINT8)(curchunk.type >> 0),
- (UINT8)(curchunk.type >> 8),
- (UINT8)(curchunk.type >> 16),
- (UINT8)(curchunk.type >> 24),
- size, offset);
-
- /* certain chunks are just containers; recurse into them */
- switch (curchunk.type)
- {
- /* basic containers */
- case CHUNKTYPE_RIFF:
- case CHUNKTYPE_LIST:
- printf("%*stype = %c%c%c%c\n", indent, "",
- (UINT8)(curchunk.listtype >> 0),
- (UINT8)(curchunk.listtype >> 8),
- (UINT8)(curchunk.listtype >> 16),
- (UINT8)(curchunk.listtype >> 24));
- recurse = TRUE;
- chunksize = 0;
- break;
- }
-
- /* print data within the chunk */
- if (chunksize > 0 && curchunk.size < 1024 * 1024)
- {
- UINT8 *data = nullptr;
- int i;
-
- /* read the data for a chunk */
- avierr = read_chunk_data(file, &curchunk, &data);
- if (avierr == AVIERR_NONE)
- {
- int bytes = MIN(512, chunksize);
- for (i = 0; i < bytes; i++)
- {
- if (i % 16 == 0) printf("%*s ", indent, "");
- printf("%02X ", data[i]);
- if (i % 16 == 15) printf("\n");
- }
- if (chunksize % 16 != 0) printf("\n");
- free(data);
- }
- }
-
- /* if we're recursing, dive down */
- if (recurse)
- printf_chunk_recursive(file, &curchunk, indent + 4);
- }
-
- /* if we didn't get a legitimate error, indicate that */
- if (avierr != AVIERR_END)
- printf("[chunk error %d]\n", avierr);
}