summaryrefslogtreecommitdiffstats
path: root/src/lib/util/aviio.cpp
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2016-03-13 13:54:57 +1100
committer Vas Crabb <vas@vastheman.com>2016-03-14 18:55:00 +1100
commit42fbb9c3967fcda37f2d9ae17d5796a79cf027b9 (patch)
treea43047ee00431e5e22bfc5f8f612ff775586e415 /src/lib/util/aviio.cpp
parent5fc27747031b6ed6f6c0582502098ebfb960be67 (diff)
Make osd_file a polymorphic class that's held with smart pointers
Make avi_file a class that's held with smart pointers, encapsulate various AVI I/O structures Make zip_file and _7z_file classes rather than having free functions everywhere Hide zip/7z class implementation behind an interface, no longer need to call close() to send back to the cache Don't dump as much crap in global namespace Add solaris PTY implementation Improve variable expansion for SDL OSD - supports ~/$FOO/${BAR} syntax Rearrange stuff so the same things are in file module for all OSDs Move file stuff into its own module 7z/zip open and destruct are still not thread-safe due to lack of interlocks around cache access Directory functions still need to be moved to file module SDL OSD may not initialise WinSock on Windows
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..8483adb24f6 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_chansamples{ 0 }
+ , m_soundbuf_chunks(0)
+ , m_soundbuf_frames(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);
}