mirror of
https://gitlab.com/mbunkus/mkvtoolnix.git
synced 2024-12-24 20:01:53 +00:00
Merged 1578 and 1580.
This commit is contained in:
parent
6d7ae72724
commit
4418dddc2c
@ -32,6 +32,9 @@
|
|||||||
* at providing the programmer an easy way to read and write RealMedia
|
* at providing the programmer an easy way to read and write RealMedia
|
||||||
* files. It does not contain any codecs for audio/video handling.
|
* files. It does not contain any codecs for audio/video handling.
|
||||||
*
|
*
|
||||||
|
* You can find a description of the RealMedia file format at
|
||||||
|
* http://www.pcisys.net/~melanson/codecs/rmff.htm
|
||||||
|
*
|
||||||
* \section License
|
* \section License
|
||||||
*
|
*
|
||||||
* The library was written by Moritz Bunkus <moritz@bunkus.org>. It is
|
* The library was written by Moritz Bunkus <moritz@bunkus.org>. It is
|
||||||
@ -52,16 +55,20 @@
|
|||||||
rmff_frame_t *frame;
|
rmff_frame_t *frame;
|
||||||
|
|
||||||
file = rmff_open_file("sample_file.rm", RMFF_OPEN_MODE_READING);
|
file = rmff_open_file("sample_file.rm", RMFF_OPEN_MODE_READING);
|
||||||
if (file == NULL) {
|
if (file != NULL) {
|
||||||
|
// Handle the error.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (rmff_read_headers(file) == RMFF_ERR_OK) {
|
||||||
// Output some general information about the tracks in the file.
|
// Output some general information about the tracks in the file.
|
||||||
// Now read all the frames.
|
// Now read all the frames.
|
||||||
while ((frame = rmff_read_next_frame(file, NULL)) != NULL) {
|
while ((frame = rmff_read_next_frame(file, NULL)) != NULL) {
|
||||||
// Do something with the frame and release it afterwards.
|
// Do something with the frame and release it afterwards.
|
||||||
rmff_release_frame(frame);
|
rmff_release_frame(frame);
|
||||||
}
|
}
|
||||||
rmff_close_file(file);
|
|
||||||
}
|
}
|
||||||
\endcode
|
rmff_close_file(file);
|
||||||
|
\endcode
|
||||||
*
|
*
|
||||||
* \section memory_handling Memory handling
|
* \section memory_handling Memory handling
|
||||||
*
|
*
|
||||||
@ -291,9 +298,10 @@ typedef struct rmff_track_t {
|
|||||||
uint32_t id;
|
uint32_t id;
|
||||||
int type;
|
int type;
|
||||||
rmff_mdpr_t mdpr_header;
|
rmff_mdpr_t mdpr_header;
|
||||||
int is_big_endian;
|
|
||||||
|
|
||||||
struct rmff_file_t *file;
|
struct rmff_file_t *file;
|
||||||
|
|
||||||
|
void *internal;
|
||||||
} rmff_track_t;
|
} rmff_track_t;
|
||||||
|
|
||||||
typedef struct rmff_file_t {
|
typedef struct rmff_file_t {
|
||||||
@ -316,6 +324,8 @@ typedef struct rmff_file_t {
|
|||||||
|
|
||||||
rmff_track_t *tracks;
|
rmff_track_t *tracks;
|
||||||
int num_tracks;
|
int num_tracks;
|
||||||
|
|
||||||
|
void *internal;
|
||||||
} rmff_file_t;
|
} rmff_file_t;
|
||||||
|
|
||||||
/** \brief No error has occured. */
|
/** \brief No error has occured. */
|
||||||
@ -441,6 +451,53 @@ rmff_frame_t *rmff_allocate_frame(uint32_t size, void *buffer);
|
|||||||
*/
|
*/
|
||||||
void rmff_release_frame(rmff_frame_t *frame);
|
void rmff_release_frame(rmff_frame_t *frame);
|
||||||
|
|
||||||
|
/** \brief Creates a new track for a file.
|
||||||
|
*
|
||||||
|
* The track will be added to the list of tracks in this file.
|
||||||
|
* \a librmff will allocate a track ID that is unique in this file.
|
||||||
|
*
|
||||||
|
* \param file The file the track will be added to.
|
||||||
|
* \returns A pointer to a newly allocated ::rmff_track_t structure or
|
||||||
|
* \c NULL in case of an error.
|
||||||
|
*/
|
||||||
|
rmff_track_t *rmff_add_track(rmff_file_t *file);
|
||||||
|
|
||||||
|
/** \brief Set some default values for RealAudio streams.
|
||||||
|
*
|
||||||
|
* Some of the fields in the \a props structure will be set to pre-defined
|
||||||
|
* values, especially the \c uknown fields. Should be used after
|
||||||
|
* rmff_add_track(rmff_file_t*).
|
||||||
|
*
|
||||||
|
* \param props A pointer to the structure whose values should be set.
|
||||||
|
* \see rmff_set_std_audio_v5_values(real_audio_v5_props_t*),
|
||||||
|
* rmff_set_std_video_values(real_video_props_t*)
|
||||||
|
*/
|
||||||
|
void rmff_set_std_audio_v4_values(real_audio_v4_props_t *props);
|
||||||
|
|
||||||
|
/** \brief Set some default values for RealAudio streams.
|
||||||
|
*
|
||||||
|
* Some of the fields in the \a props structure will be set to pre-defined
|
||||||
|
* values, especially the \c uknown fields. Should be used after
|
||||||
|
* rmff_add_track(rmff_file_t*).
|
||||||
|
*
|
||||||
|
* \param props A pointer to the structure whose values should be set.
|
||||||
|
* \see rmff_set_std_audio_v4_values(real_audio_v5_props_t*),
|
||||||
|
* rmff_set_std_video_values(real_video_props_t*)
|
||||||
|
*/
|
||||||
|
void rmff_set_std_audio_v5_values(real_audio_v5_props_t *props);
|
||||||
|
|
||||||
|
/** \brief Set some default values for RealVideo streams.
|
||||||
|
*
|
||||||
|
* Some of the fields in the \a props structure will be set to pre-defined
|
||||||
|
* values, especially the \c uknown fields. Should be used after
|
||||||
|
* rmff_add_track(rmff_file_t*).
|
||||||
|
*
|
||||||
|
* \param props A pointer to the structure whose values should be set.
|
||||||
|
* \see rmff_set_std_audio_v4_values(real_audio_v4_props_t*),
|
||||||
|
* rmff_set_std_audio_v5_values(real_audio_v5_props_t*)
|
||||||
|
*/
|
||||||
|
void rmff_set_std_video_values(real_video_props_t *props);
|
||||||
|
|
||||||
/** \brief Sets the contents of the \link ::rmff_cont_t CONT file header
|
/** \brief Sets the contents of the \link ::rmff_cont_t CONT file header
|
||||||
* \endlink.
|
* \endlink.
|
||||||
*
|
*
|
||||||
@ -488,6 +545,12 @@ void rmff_set_track_data(rmff_track_t *track, const char *name,
|
|||||||
void rmff_set_track_specific_data(rmff_track_t *track,
|
void rmff_set_track_specific_data(rmff_track_t *track,
|
||||||
const unsigned char *data, uint32_t size);
|
const unsigned char *data, uint32_t size);
|
||||||
|
|
||||||
|
int rmff_write_headers(rmff_file_t *file);
|
||||||
|
|
||||||
|
int rmff_fix_headers(rmff_file_t *file);
|
||||||
|
|
||||||
|
void rmff_copy_track_headers(rmff_track_t *dst, rmff_track_t *src);
|
||||||
|
|
||||||
/** \brief The error code of the last function call.
|
/** \brief The error code of the last function call.
|
||||||
* Contains the last error code for a function that failed. If a function
|
* Contains the last error code for a function that failed. If a function
|
||||||
* succeeded it usually does not reset \a rmff_last_error to \c RMFF_ERR_OK.
|
* succeeded it usually does not reset \a rmff_last_error to \c RMFF_ERR_OK.
|
||||||
|
331
librmff/rmff.c
331
librmff/rmff.c
@ -27,6 +27,26 @@
|
|||||||
|
|
||||||
#include "librmff.h"
|
#include "librmff.h"
|
||||||
|
|
||||||
|
typedef struct rmff_file_internal_t {
|
||||||
|
uint32_t max_bit_rate;
|
||||||
|
uint32_t avg_bit_rate;
|
||||||
|
uint32_t max_packet_size;
|
||||||
|
uint32_t avg_packet_size;
|
||||||
|
uint32_t highest_timecode;
|
||||||
|
uint32_t num_packets;
|
||||||
|
uint32_t data_offset;
|
||||||
|
uint32_t index_offset;
|
||||||
|
} rmff_file_internal_t;
|
||||||
|
|
||||||
|
typedef struct rmff_track_internal_t {
|
||||||
|
uint32_t max_bit_rate;
|
||||||
|
uint32_t avg_bit_rate;
|
||||||
|
uint32_t max_packet_size;
|
||||||
|
uint32_t avg_packet_size;
|
||||||
|
uint32_t highest_timecode;
|
||||||
|
uint32_t num_packets;
|
||||||
|
} rmff_track_internal_t;
|
||||||
|
|
||||||
int rmff_last_error = RMFF_ERR_OK;
|
int rmff_last_error = RMFF_ERR_OK;
|
||||||
const char *rmff_last_error_msg = NULL;
|
const char *rmff_last_error_msg = NULL;
|
||||||
static const char *rmff_std_error_messages[] = {
|
static const char *rmff_std_error_messages[] = {
|
||||||
@ -89,8 +109,8 @@ rmff_get_uint32_be(const void *buf) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
rmff_put_uin16_be(void *buf,
|
rmff_put_uint16_be(void *buf,
|
||||||
uint16_t value) {
|
uint16_t value) {
|
||||||
unsigned char *tmp;
|
unsigned char *tmp;
|
||||||
|
|
||||||
tmp = (unsigned char *) buf;
|
tmp = (unsigned char *) buf;
|
||||||
@ -100,8 +120,8 @@ rmff_put_uin16_be(void *buf,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
rmff_put_uin32_be(void *buf,
|
rmff_put_uint32_be(void *buf,
|
||||||
uint32_t value) {
|
uint32_t value) {
|
||||||
unsigned char *tmp;
|
unsigned char *tmp;
|
||||||
|
|
||||||
tmp = (unsigned char *) buf;
|
tmp = (unsigned char *) buf;
|
||||||
@ -115,8 +135,13 @@ rmff_put_uin32_be(void *buf,
|
|||||||
#define read_uint8() file_read_uint8(io, fh)
|
#define read_uint8() file_read_uint8(io, fh)
|
||||||
#define read_uint16_be() file_read_uint16_be(io, fh)
|
#define read_uint16_be() file_read_uint16_be(io, fh)
|
||||||
#define read_uint32_be() file_read_uint32_be(io, fh)
|
#define read_uint32_be() file_read_uint32_be(io, fh)
|
||||||
#define read_uint16_be_to(addr) rmff_put_uin16_be(addr, read_uint16_be())
|
#define read_uint16_be_to(addr) rmff_put_uint16_be(addr, read_uint16_be())
|
||||||
#define read_uint32_be_to(addr) rmff_put_uin32_be(addr, read_uint32_be())
|
#define read_uint32_be_to(addr) rmff_put_uint32_be(addr, read_uint32_be())
|
||||||
|
#define write_uint8(v) file_write_uint8(io, fh, v)
|
||||||
|
#define write_uint16_be(v) file_write_uint16_be(io, fh, v)
|
||||||
|
#define write_uint32_be(v) file_write_uint32_be(io, fh, v)
|
||||||
|
#define write_uint16_be_from(addr) write_uint16_be(rmff_get_uint16_be(addr))
|
||||||
|
#define write_uint32_be_from(addr) write_uint32_be(rmff_get_uint32_be(addr))
|
||||||
#define get_fourcc(b) rmff_get_uint32_be(b)
|
#define get_fourcc(b) rmff_get_uint32_be(b)
|
||||||
|
|
||||||
static uint8_t
|
static uint8_t
|
||||||
@ -146,6 +171,33 @@ file_read_uint32_be(mb_file_io_t *io,
|
|||||||
return rmff_get_uint32_be(tmp);
|
return rmff_get_uint32_be(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
file_write_uint8(mb_file_io_t *io,
|
||||||
|
void *fh,
|
||||||
|
uint8_t value) {
|
||||||
|
return io->write(fh, &value, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
file_write_uint16_be(mb_file_io_t *io,
|
||||||
|
void *fh,
|
||||||
|
uint16_t value) {
|
||||||
|
unsigned char tmp[2];
|
||||||
|
|
||||||
|
rmff_put_uint16_be(tmp, value);
|
||||||
|
return io->write(fh, &tmp, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
file_write_uint32_be(mb_file_io_t *io,
|
||||||
|
void *fh,
|
||||||
|
uint32_t value) {
|
||||||
|
unsigned char tmp[4];
|
||||||
|
|
||||||
|
rmff_put_uint32_be(tmp, value);
|
||||||
|
return io->write(fh, &tmp, 4);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
die(const char *fmt,
|
die(const char *fmt,
|
||||||
...) {
|
...) {
|
||||||
@ -268,6 +320,7 @@ open_file_for_reading(const char *path,
|
|||||||
file->size = io->tell(file_h);
|
file->size = io->tell(file_h);
|
||||||
io->seek(file_h, 4, SEEK_SET);
|
io->seek(file_h, 4, SEEK_SET);
|
||||||
file->open_mode = RMFF_OPEN_MODE_READING;
|
file->open_mode = RMFF_OPEN_MODE_READING;
|
||||||
|
file->internal = safecalloc(sizeof(rmff_file_internal_t));
|
||||||
|
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
@ -294,6 +347,7 @@ open_file_for_writing(const char *path,
|
|||||||
file->io = io;
|
file->io = io;
|
||||||
file->size = -1;
|
file->size = -1;
|
||||||
file->open_mode = RMFF_OPEN_MODE_WRITING;
|
file->open_mode = RMFF_OPEN_MODE_WRITING;
|
||||||
|
file->internal = safecalloc(sizeof(rmff_file_internal_t));
|
||||||
|
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
@ -325,6 +379,7 @@ rmff_free_track_data(rmff_track_t *track) {
|
|||||||
safefree(track->mdpr_header.name);
|
safefree(track->mdpr_header.name);
|
||||||
safefree(track->mdpr_header.mime_type);
|
safefree(track->mdpr_header.mime_type);
|
||||||
safefree(track->mdpr_header.type_specific_data);
|
safefree(track->mdpr_header.type_specific_data);
|
||||||
|
safefree(track->internal);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -342,6 +397,7 @@ rmff_close_file(rmff_file_t *file) {
|
|||||||
safefree(file->cont_header.author);
|
safefree(file->cont_header.author);
|
||||||
safefree(file->cont_header.copyright);
|
safefree(file->cont_header.copyright);
|
||||||
safefree(file->cont_header.comment);
|
safefree(file->cont_header.comment);
|
||||||
|
safefree(file->internal);
|
||||||
file->io->close(file->handle);
|
file->io->close(file->handle);
|
||||||
safefree(file);
|
safefree(file);
|
||||||
}
|
}
|
||||||
@ -415,22 +471,22 @@ rmff_read_headers(rmff_file_t *file) {
|
|||||||
|
|
||||||
size = read_uint16_be(); /* title_len */
|
size = read_uint16_be(); /* title_len */
|
||||||
if (size > 0) {
|
if (size > 0) {
|
||||||
cont->title = (char *)safemalloc(size + 1);
|
cont->title = (char *)safecalloc(size + 1);
|
||||||
io->read(fh, cont->title, size);
|
io->read(fh, cont->title, size);
|
||||||
}
|
}
|
||||||
size = read_uint16_be(); /* author_len */
|
size = read_uint16_be(); /* author_len */
|
||||||
if (size > 0) {
|
if (size > 0) {
|
||||||
cont->author = (char *)safemalloc(size + 1);
|
cont->author = (char *)safecalloc(size + 1);
|
||||||
io->read(fh, cont->author, size);
|
io->read(fh, cont->author, size);
|
||||||
}
|
}
|
||||||
size = read_uint16_be(); /* copyright_len */
|
size = read_uint16_be(); /* copyright_len */
|
||||||
if (size > 0) {
|
if (size > 0) {
|
||||||
cont->copyright = (char *)safemalloc(size + 1);
|
cont->copyright = (char *)safecalloc(size + 1);
|
||||||
io->read(fh, cont->copyright, size);
|
io->read(fh, cont->copyright, size);
|
||||||
}
|
}
|
||||||
size = read_uint16_be(); /* comment_len */
|
size = read_uint16_be(); /* comment_len */
|
||||||
if (size > 0) {
|
if (size > 0) {
|
||||||
cont->comment = (char *)safemalloc(size + 1);
|
cont->comment = (char *)safecalloc(size + 1);
|
||||||
io->read(fh, cont->comment, size);
|
io->read(fh, cont->comment, size);
|
||||||
}
|
}
|
||||||
file->cont_header_present = 1;
|
file->cont_header_present = 1;
|
||||||
@ -459,7 +515,7 @@ rmff_read_headers(rmff_file_t *file) {
|
|||||||
io->read(fh, mdpr->mime_type, size);
|
io->read(fh, mdpr->mime_type, size);
|
||||||
}
|
}
|
||||||
size = read_uint32_be(); /* type_specific_size */
|
size = read_uint32_be(); /* type_specific_size */
|
||||||
mdpr->type_specific_size = size;
|
rmff_put_uint32_be(&mdpr->type_specific_size, size);
|
||||||
if (size > 0) {
|
if (size > 0) {
|
||||||
mdpr->type_specific_data = (unsigned char *)safemalloc(size);
|
mdpr->type_specific_data = (unsigned char *)safemalloc(size);
|
||||||
io->read(fh, mdpr->type_specific_data, size);
|
io->read(fh, mdpr->type_specific_data, size);
|
||||||
@ -480,6 +536,7 @@ rmff_read_headers(rmff_file_t *file) {
|
|||||||
"data too small", RMFF_ERR_DATA);
|
"data too small", RMFF_ERR_DATA);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
track.internal = safecalloc(sizeof(rmff_track_internal_t));
|
||||||
file->tracks =
|
file->tracks =
|
||||||
(rmff_track_t *)saferealloc(file->tracks, (file->num_tracks + 1) *
|
(rmff_track_t *)saferealloc(file->tracks, (file->num_tracks + 1) *
|
||||||
sizeof(rmff_track_t));
|
sizeof(rmff_track_t));
|
||||||
@ -660,5 +717,257 @@ rmff_set_track_specific_data(rmff_track_t *track,
|
|||||||
safefree(track->mdpr_header.type_specific_data);
|
safefree(track->mdpr_header.type_specific_data);
|
||||||
track->mdpr_header.type_specific_data =
|
track->mdpr_header.type_specific_data =
|
||||||
(unsigned char *)safememdup(data, size);
|
(unsigned char *)safememdup(data, size);
|
||||||
|
rmff_put_uint32_be(&track->mdpr_header.type_specific_size, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rmff_track_t *
|
||||||
|
rmff_add_track(rmff_file_t *file) {
|
||||||
|
rmff_track_t track;
|
||||||
|
int i, id, found;
|
||||||
|
|
||||||
|
if ((file == NULL) || (file->open_mode != RMFF_OPEN_MODE_WRITING))
|
||||||
|
return (rmff_track_t *)set_error(RMFF_ERR_PARAMETERS, NULL, 0);
|
||||||
|
|
||||||
|
id = 0;
|
||||||
|
do {
|
||||||
|
found = 0;
|
||||||
|
for (i = 0; i < file->num_tracks; i++)
|
||||||
|
if (file->tracks[i].id == id) {
|
||||||
|
found = 1;
|
||||||
|
id++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (found);
|
||||||
|
|
||||||
|
memset(&track, 0, sizeof(rmff_track_t));
|
||||||
|
track.id = id;
|
||||||
|
track.file = file;
|
||||||
|
|
||||||
|
file->tracks =
|
||||||
|
(rmff_track_t *)saferealloc(file->tracks, (file->num_tracks + 1) *
|
||||||
|
sizeof(rmff_track_t));
|
||||||
|
file->tracks[file->num_tracks] = track;
|
||||||
|
file->num_tracks++;
|
||||||
|
|
||||||
|
return &file->tracks[file->num_tracks - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rmff_set_std_audio_v4_values(real_audio_v4_props_t *props) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rmff_set_std_audio_v5_values(real_audio_v5_props_t *props) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rmff_set_std_video_values(real_video_props_t *props) {
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
write_prop_header(rmff_file_t *file) {
|
||||||
|
void *fh;
|
||||||
|
mb_file_io_t *io;
|
||||||
|
int bw;
|
||||||
|
|
||||||
|
io = file->io;
|
||||||
|
fh = file->handle;
|
||||||
|
|
||||||
|
/* Write the PROP header. */
|
||||||
|
bw = write_uint32_be(rmffFOURCC('P', 'R', 'O', 'P'));
|
||||||
|
bw += write_uint32_be(0x32); /* object_size */
|
||||||
|
bw += write_uint16_be(0); /* object_version */
|
||||||
|
|
||||||
|
bw += write_uint32_be_from(&file->prop_header.max_bit_rate);
|
||||||
|
bw += write_uint32_be_from(&file->prop_header.avg_bit_rate);
|
||||||
|
bw += write_uint32_be_from(&file->prop_header.max_packet_size);
|
||||||
|
bw += write_uint32_be_from(&file->prop_header.avg_packet_size);
|
||||||
|
bw += write_uint32_be_from(&file->prop_header.num_packets);
|
||||||
|
bw += write_uint32_be_from(&file->prop_header.duration);
|
||||||
|
bw += write_uint32_be_from(&file->prop_header.preroll);
|
||||||
|
bw += write_uint32_be_from(&file->prop_header.index_offset);
|
||||||
|
bw += write_uint32_be_from(&file->prop_header.data_offset);
|
||||||
|
bw += write_uint16_be_from(&file->prop_header.num_streams);
|
||||||
|
bw += write_uint16_be_from(&file->prop_header.flags);
|
||||||
|
|
||||||
|
return bw;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
write_cont_header(rmff_file_t *file) {
|
||||||
|
void *fh;
|
||||||
|
mb_file_io_t *io;
|
||||||
|
int bw, wanted_len, title_len, author_len, copyright_len, comment_len;
|
||||||
|
|
||||||
|
io = file->io;
|
||||||
|
fh = file->handle;
|
||||||
|
|
||||||
|
if (file->cont_header.title == NULL)
|
||||||
|
title_len = 0;
|
||||||
|
else
|
||||||
|
title_len = strlen(file->cont_header.title);
|
||||||
|
if (file->cont_header.author == NULL)
|
||||||
|
author_len = 0;
|
||||||
|
else
|
||||||
|
author_len = strlen(file->cont_header.author);
|
||||||
|
if (file->cont_header.copyright == NULL)
|
||||||
|
copyright_len = 0;
|
||||||
|
else
|
||||||
|
copyright_len = strlen(file->cont_header.copyright);
|
||||||
|
if (file->cont_header.comment == NULL)
|
||||||
|
comment_len = 0;
|
||||||
|
else
|
||||||
|
comment_len = strlen(file->cont_header.comment);
|
||||||
|
|
||||||
|
wanted_len = 4 + 4 + 2 + 4 * 2 + title_len + author_len + copyright_len +
|
||||||
|
comment_len;
|
||||||
|
|
||||||
|
/* Write the CONT header. */
|
||||||
|
bw = write_uint32_be(rmffFOURCC('C', 'O', 'N', 'T'));
|
||||||
|
bw += write_uint32_be(wanted_len); /* object_size */
|
||||||
|
bw += write_uint16_be(0); /* object_version */
|
||||||
|
bw += write_uint16_be(title_len);
|
||||||
|
if (file->cont_header.title != NULL)
|
||||||
|
bw += io->write(fh, file->cont_header.title, title_len);
|
||||||
|
bw += write_uint16_be(author_len);
|
||||||
|
if (file->cont_header.author != NULL)
|
||||||
|
bw += io->write(fh, file->cont_header.author, author_len);
|
||||||
|
bw += write_uint16_be(copyright_len);
|
||||||
|
if (file->cont_header.copyright != NULL)
|
||||||
|
bw += io->write(fh, file->cont_header.copyright, copyright_len);
|
||||||
|
bw += write_uint16_be(comment_len);
|
||||||
|
if (file->cont_header.comment != NULL)
|
||||||
|
bw += io->write(fh, file->cont_header.comment, comment_len);
|
||||||
|
|
||||||
|
if (bw == wanted_len)
|
||||||
|
return 0;
|
||||||
|
return set_error(RMFF_ERR_IO, "Could not write the CONT header",
|
||||||
|
RMFF_ERR_IO);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
write_mdpr_header(rmff_track_t *track) {
|
||||||
|
void *fh;
|
||||||
|
mb_file_io_t *io;
|
||||||
|
int bw, wanted_len, name_len, mime_type_len;
|
||||||
|
|
||||||
|
io = track->file->io;
|
||||||
|
fh = track->file->handle;
|
||||||
|
|
||||||
|
rmff_put_uint16_be(&track->mdpr_header.id, track->id);
|
||||||
|
if (track->mdpr_header.name == NULL)
|
||||||
|
name_len = 0;
|
||||||
|
else
|
||||||
|
name_len = strlen(track->mdpr_header.name);
|
||||||
|
if (track->mdpr_header.mime_type == NULL)
|
||||||
|
mime_type_len = 0;
|
||||||
|
else
|
||||||
|
mime_type_len = strlen(track->mdpr_header.mime_type);
|
||||||
|
|
||||||
|
wanted_len = 4 + 4 + 2 + 2 + 7 * 4 + 1 + name_len + 1 + mime_type_len +
|
||||||
|
4 + rmff_get_uint32_be(&track->mdpr_header.type_specific_size);
|
||||||
|
|
||||||
|
/* Write the MDPR header. */
|
||||||
|
bw = write_uint32_be(rmffFOURCC('M', 'D', 'P', 'R'));
|
||||||
|
bw += write_uint32_be(wanted_len); /* object_size */
|
||||||
|
bw += write_uint16_be(0); /* object_version */
|
||||||
|
|
||||||
|
bw += write_uint16_be_from(&track->mdpr_header.id);
|
||||||
|
bw += write_uint32_be_from(&track->mdpr_header.max_bit_rate);
|
||||||
|
bw += write_uint32_be_from(&track->mdpr_header.avg_bit_rate);
|
||||||
|
bw += write_uint32_be_from(&track->mdpr_header.max_packet_size);
|
||||||
|
bw += write_uint32_be_from(&track->mdpr_header.avg_packet_size);
|
||||||
|
bw += write_uint32_be_from(&track->mdpr_header.start_time);
|
||||||
|
bw += write_uint32_be_from(&track->mdpr_header.preroll);
|
||||||
|
bw += write_uint32_be_from(&track->mdpr_header.duration);
|
||||||
|
bw += write_uint8(name_len);
|
||||||
|
if (track->mdpr_header.name != NULL)
|
||||||
|
bw += io->write(fh, track->mdpr_header.name, name_len);
|
||||||
|
bw += write_uint8(mime_type_len);
|
||||||
|
if (track->mdpr_header.mime_type != NULL)
|
||||||
|
bw += io->write(fh, track->mdpr_header.mime_type, mime_type_len);
|
||||||
|
bw += write_uint32_be_from(&track->mdpr_header.type_specific_size);
|
||||||
|
if (track->mdpr_header.type_specific_data != NULL)
|
||||||
|
bw +=
|
||||||
|
io->write(fh, track->mdpr_header.type_specific_data,
|
||||||
|
rmff_get_uint32_be(&track->mdpr_header.type_specific_size));
|
||||||
|
|
||||||
|
if (wanted_len != bw)
|
||||||
|
return set_error(RMFF_ERR_IO, "Could not write the MDPR header",
|
||||||
|
RMFF_ERR_IO);
|
||||||
|
return RMFF_ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
rmff_write_headers(rmff_file_t *file) {
|
||||||
|
void *fh;
|
||||||
|
mb_file_io_t *io;
|
||||||
|
int i, bw;
|
||||||
|
rmff_file_internal_t *fint;
|
||||||
|
const char *signature = ".RMF";
|
||||||
|
|
||||||
|
if ((file == NULL) || (file->open_mode != RMFF_OPEN_MODE_WRITING))
|
||||||
|
return set_error(RMFF_ERR_PARAMETERS, NULL, RMFF_ERR_PARAMETERS);
|
||||||
|
|
||||||
|
io = file->io;
|
||||||
|
fh = file->handle;
|
||||||
|
io->seek(fh, 0, SEEK_SET);
|
||||||
|
|
||||||
|
/* Write the file header. */
|
||||||
|
bw = io->write(fh, signature, 4);
|
||||||
|
bw += write_uint32_be(0x12); /* header_size */
|
||||||
|
bw += write_uint16_be(1); /* object_version */
|
||||||
|
bw += write_uint32_be(0); /* file_version */
|
||||||
|
bw += write_uint32_be(0); /* temporary: num_headers */
|
||||||
|
|
||||||
|
if (bw != 18)
|
||||||
|
return set_error(RMFF_ERR_IO, "Could not write the file header",
|
||||||
|
RMFF_ERR_IO);
|
||||||
|
|
||||||
|
rmff_put_uint16_be(&file->prop_header.num_streams, file->num_tracks);
|
||||||
|
bw = write_prop_header(file);
|
||||||
|
if (bw != 0x32)
|
||||||
|
return set_error(RMFF_ERR_IO, "Could not write the PROP header",
|
||||||
|
RMFF_ERR_IO);
|
||||||
|
|
||||||
|
if (file->cont_header_present) {
|
||||||
|
bw = write_cont_header(file);
|
||||||
|
if (bw != RMFF_ERR_OK)
|
||||||
|
return bw;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < file->num_tracks; i++) {
|
||||||
|
bw = write_mdpr_header(&file->tracks[i]);
|
||||||
|
if (bw < RMFF_ERR_OK)
|
||||||
|
return bw;
|
||||||
|
}
|
||||||
|
|
||||||
|
fint = (rmff_file_internal_t *)file->internal;
|
||||||
|
fint->data_offset = io->tell(fh);
|
||||||
|
|
||||||
|
return RMFF_ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
rmff_fix_headers(rmff_file_t *file) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rmff_copy_track_headers(rmff_track_t *dst,
|
||||||
|
rmff_track_t *src) {
|
||||||
|
if ((dst == NULL) || (src == NULL))
|
||||||
|
return;
|
||||||
|
|
||||||
|
rmff_free_track_data(dst);
|
||||||
|
memcpy(&dst->mdpr_header, &src->mdpr_header, sizeof(rmff_mdpr_t));
|
||||||
|
dst->mdpr_header.name = safestrdup(src->mdpr_header.name);
|
||||||
|
dst->mdpr_header.mime_type = safestrdup(src->mdpr_header.mime_type);
|
||||||
|
dst->mdpr_header.type_specific_data = (unsigned char *)
|
||||||
|
safememdup(src->mdpr_header.type_specific_data,
|
||||||
|
rmff_get_uint32_be(&src->mdpr_header.type_specific_size));
|
||||||
|
dst->internal = (unsigned char *)safememdup(src->internal,
|
||||||
|
sizeof(rmff_track_internal_t));
|
||||||
|
dst->type = src->type;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user