mirror of
https://gitlab.com/mbunkus/mkvtoolnix.git
synced 2024-12-24 03:42:53 +00:00
Merged 1572:1575.
This commit is contained in:
parent
484b0c2fd9
commit
6d7ae72724
@ -24,6 +24,82 @@
|
||||
* \author Moritz Bunkus <moritz@bunkus.org>
|
||||
*/
|
||||
|
||||
/** \mainpage
|
||||
*
|
||||
* \section Introduction
|
||||
*
|
||||
* \a librmff is short for 'RealMedia file format access library'. It aims
|
||||
* at providing the programmer an easy way to read and write RealMedia
|
||||
* files. It does not contain any codecs for audio/video handling.
|
||||
*
|
||||
* \section License
|
||||
*
|
||||
* The library was written by Moritz Bunkus <moritz@bunkus.org>. It is
|
||||
* licensed under the terms of the GNU Lesser General Public License (GNU
|
||||
* LGPL) which can be found in the file COPYING.
|
||||
*
|
||||
* \section Usage
|
||||
*
|
||||
* Here are very short samples of how to use the library.
|
||||
*
|
||||
* \subsection reading_existing Reading an existing file
|
||||
*
|
||||
* Reading an existing file requires four steps: Opening the file, reading
|
||||
* the headers, reading all the frames and closing the file.
|
||||
*
|
||||
* \code
|
||||
rmff_file_t *file;
|
||||
rmff_frame_t *frame;
|
||||
|
||||
file = rmff_open_file("sample_file.rm", RMFF_OPEN_MODE_READING);
|
||||
if (file == NULL) {
|
||||
// Output some general information about the tracks in the file.
|
||||
// Now read all the frames.
|
||||
while ((frame = rmff_read_next_frame(file, NULL)) != NULL) {
|
||||
// Do something with the frame and release it afterwards.
|
||||
rmff_release_frame(frame);
|
||||
}
|
||||
rmff_close_file(file);
|
||||
}
|
||||
\endcode
|
||||
*
|
||||
* \section memory_handling Memory handling
|
||||
*
|
||||
* Generally \a librmff allocates and frees memory itself. You should
|
||||
* \b never mess with pointers inside the structures directly but use
|
||||
* the provided functions for manipulating it. There's one exception to
|
||||
* this rule: the frame handling.
|
||||
*
|
||||
* The functions rmff_read_next_frame(rmff_file_t*,void*),
|
||||
* rmff_release_frame(rmff_frame_t*) and
|
||||
* rmff_allocate_frame(uint32_t,void*) allow the application to provide its
|
||||
* own buffers for storing the frame contents. \a librmff will not copy
|
||||
* this memory further. It will read directly into the buffer or write directly
|
||||
* from the buffer into the file.
|
||||
*
|
||||
* Example: \code
|
||||
rmff_frame_t *frame;
|
||||
unsigned char *buffer,
|
||||
int size;
|
||||
|
||||
while (1) {
|
||||
// Get the next frame's size.
|
||||
size = rmff_get_next_frame_size(file);
|
||||
// Have we reached the end of the file?
|
||||
if (size == -1)
|
||||
break;
|
||||
// Allocate enough space for this frame and let librmff read directly
|
||||
// into it.
|
||||
buffer = (unsigned char *)malloc(size);
|
||||
frame = rmff_read_next_frame(file, buffer);
|
||||
// Now do something with the buffer. Afterwards release the frame.
|
||||
rmff_release_frame(frame);
|
||||
// The buffer is still allocated. So free it now.
|
||||
free(buffer);
|
||||
}
|
||||
\endcode
|
||||
*/
|
||||
|
||||
#ifndef __RMFF_H
|
||||
#define __RMFF_H
|
||||
|
||||
@ -36,9 +112,14 @@ extern "C" {
|
||||
|
||||
#include "mb_file_io.h"
|
||||
|
||||
/** \brief Contains the PROP file header.
|
||||
/** \brief The global PROP file header.
|
||||
*
|
||||
* This header is mandatory for a RealMedia file. It contains statistical
|
||||
* and global data. Each member is in big endian.
|
||||
* and global data. The values are stored in big endian byte order.
|
||||
* The application should use the functions
|
||||
* rmff_get_uint16_be(const void*), rmff_get_uint32_be(const void*),
|
||||
* rmff_put_uint16_be(void*,uint16_t) and
|
||||
* rmff_put_uint32_be(void*,uint32_t) for accessing the members.
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t max_bit_rate;
|
||||
@ -55,9 +136,10 @@ typedef struct {
|
||||
} rmff_prop_t;
|
||||
|
||||
/** \brief Comments about the file in question.
|
||||
*
|
||||
* This structure contains the parsed values of the CONT header. These
|
||||
* strings must not be modified by the application. The function
|
||||
* rmff_set_cont_header(const_char*,const_char*,const_char*,const_char*)
|
||||
* rmff_set_cont_header(rmff_file_t*,const char*,const char*,const char*,const char*)
|
||||
* must be used instead.
|
||||
*/
|
||||
typedef struct {
|
||||
@ -67,18 +149,59 @@ typedef struct {
|
||||
char *comment;
|
||||
} rmff_cont_t;
|
||||
|
||||
/** \brief The MDPR track headers.
|
||||
*
|
||||
* Each track in a RealMedia file contains the MDPR header. The values
|
||||
* are stored in big endian byte order.
|
||||
* The application should use the functions
|
||||
* rmff_get_uint16_be(const void*), rmff_get_uint32_be(const void*),
|
||||
* rmff_put_uint16_be(void*,uint16_t) and
|
||||
* rmff_put_uint32_be(void*,uint32_t) for accessing the members.
|
||||
*/
|
||||
typedef struct {
|
||||
/** \brief The track number. It is unique regarding the file. */
|
||||
uint16_t id;
|
||||
/** \brief The maximum bitrate in bit/second.
|
||||
*
|
||||
* When creating a file this value will
|
||||
* be updated automatically by the library. */
|
||||
uint32_t max_bit_rate;
|
||||
/** \brief The average bitrate in bit/second.
|
||||
*
|
||||
* When creating a file this value will
|
||||
* be updated automatically by the library. */
|
||||
uint32_t avg_bit_rate;
|
||||
/** \brief The maximum packet size in bytes.
|
||||
*
|
||||
* When creating a file this value will
|
||||
* be updated automatically by the library. */
|
||||
uint32_t max_packet_size;
|
||||
/** \brief The average packet size in bytes.
|
||||
*
|
||||
* When creating a file this value will
|
||||
* be updated automatically by the library. */
|
||||
uint32_t avg_packet_size;
|
||||
uint32_t start_time;
|
||||
uint32_t preroll;
|
||||
uint32_t duration;
|
||||
/** \brief The track's name.
|
||||
*
|
||||
* Use the rmff_set_track_data(rmff_track_t*,const char*,const char*)
|
||||
* function for setting it. */
|
||||
char *name;
|
||||
/** \brief The track's MIME type.
|
||||
*
|
||||
* Use the rmff_set_track_data(rmff_track_t*,const char*,const char*)
|
||||
* function for setting it. */
|
||||
char *mime_type;
|
||||
/** \brief The size of the track specific data in bytes. */
|
||||
uint32_t type_specific_size;
|
||||
/** \brief Track type specific data.
|
||||
*
|
||||
* Use the
|
||||
* rmff_set_track_specific_data(rmff_track_t*,const unsigned char*,uint32_t)
|
||||
* function for setting it. It usually contains a ::real_video_props_t or
|
||||
* ::real_audio_v4_props_t structure. */
|
||||
unsigned char *type_specific_data;
|
||||
} rmff_mdpr_t;
|
||||
|
||||
@ -162,7 +285,7 @@ typedef struct rmff_frame_t {
|
||||
/** \brief The track contains video data. */
|
||||
#define RMFF_TRACK_TYPE_VIDEO 2
|
||||
|
||||
struct rmff_file_t ;
|
||||
struct rmff_file_t;
|
||||
|
||||
typedef struct rmff_track_t {
|
||||
uint32_t id;
|
||||
@ -210,15 +333,18 @@ typedef struct rmff_file_t {
|
||||
/** \brief An error has occured for which \c errno should be consulted. */
|
||||
#define RMFF_ERR_CHECK_ERRNO -6
|
||||
|
||||
#define rmffFOURCC(a, b, c, d) (uint32_t)((((unsigned char)a) << 24) + \
|
||||
(((unsigned char)b) << 16) + \
|
||||
(((unsigned char)c) << 8) + \
|
||||
((unsigned char)d))
|
||||
/** \brief Convert the four bytes into a 'FOURCC' uint32. */
|
||||
#define rmffFOURCC(a, b, c, d) \
|
||||
(uint32_t)((((unsigned char)a) << 24) + \
|
||||
(((unsigned char)b) << 16) + \
|
||||
(((unsigned char)c) << 8) + \
|
||||
((unsigned char)d))
|
||||
|
||||
#define RMFF_OPEN_MODE_READING 0
|
||||
#define RMFF_OPEN_MODE_WRITING 1
|
||||
|
||||
/** \brief Opens a RealMedia file for reading or writing.
|
||||
*
|
||||
* Can be used to open an existing file for reading or for creating a new
|
||||
* file. The file headers will neither be read nor written automatically.
|
||||
* This function uses the standard file I/O functions provided by the
|
||||
@ -226,16 +352,17 @@ typedef struct rmff_file_t {
|
||||
*
|
||||
* \param path the name of the file that should be opened
|
||||
* \param mode either ::RMFF_OPEN_MODE_READING or ::RMFF_OPEN_MODE_WRITING
|
||||
* \returns a pointer to \c rmff_file_t structure or \c NULL if an error
|
||||
* \returns a pointer to ::rmff_file_t structure or \c NULL if an error
|
||||
* occured. In the latter case ::rmff_last_error will be set.
|
||||
* \see rmff_open_file_with_io
|
||||
*/
|
||||
rmff_file_t *rmff_open_file(const char *path, int mode);
|
||||
|
||||
/** \brief Opens a RealMedia file for reading or writing.
|
||||
*
|
||||
* Can be used to open an existing file for reading or for creating a new
|
||||
* file. The file headers will neither be read nor written automatically.
|
||||
* This function uses I/O functions provided by the \c io parameter.
|
||||
* This function uses I/O functions provided by the \a io parameter.
|
||||
*
|
||||
* \param path the name of the file that should be opened
|
||||
* \param mode either ::RMFF_OPEN_MODE_READING or ::RMFF_OPEN_MODE_WRITING
|
||||
@ -248,8 +375,9 @@ rmff_file_t *rmff_open_file_with_io(const char *path, int mode,
|
||||
mb_file_io_t *io);
|
||||
|
||||
/** \brief Close the file and release all resources.
|
||||
*
|
||||
* Closes the file and releases all resources associated with it, including
|
||||
* the \c file structure. If the file was open for writing then
|
||||
* the ::rmff_file_t structure. If the file was open for writing then
|
||||
* rmff_write_headers() should be called prior to closing the file as
|
||||
* \c rmff_close_file does not fix the headers itself.
|
||||
*
|
||||
@ -258,6 +386,7 @@ rmff_file_t *rmff_open_file_with_io(const char *path, int mode,
|
||||
void rmff_close_file(rmff_file_t *file);
|
||||
|
||||
/** \brief Reads the file and track headers.
|
||||
*
|
||||
* This function should be called after directly after opening it for reading.
|
||||
* It will try to read the file and track headers and position the file pointer
|
||||
* right before the first data packet.
|
||||
@ -277,30 +406,47 @@ int rmff_read_headers(rmff_file_t *file);
|
||||
int rmff_get_next_frame_size(rmff_file_t *file);
|
||||
|
||||
/** \brief Reads the next frame from the file.
|
||||
*
|
||||
* The frame must be released by rmff_release_frame(rmff_frame_t*).
|
||||
*
|
||||
* \param file The file to read from.
|
||||
* \param buffer A buffer to read the frame into. This parameter may be
|
||||
* \c NULL in which case the buffer will be allocated by the library.
|
||||
* If the application provides the buffer it must be large enough.
|
||||
* The function rmff_get_next_frame_size() can be used in this case.
|
||||
* The function rmff_get_next_frame_size(rmff_file_t*) can be used in this
|
||||
* case.
|
||||
* \returns a pointer to a ::rmff_frame_t structure containing the frame
|
||||
* and its metadata on success or \c NULL if the call failed. This frame
|
||||
* must be freed with rmff_release_frame(rmff_frame_t*).
|
||||
*/
|
||||
rmff_frame_t *rmff_read_next_frame(rmff_file_t *file, void *buffer);
|
||||
|
||||
/** \brief Allocates a frame and possibly a buffer for its contents.
|
||||
*
|
||||
* \param size The size of this frame.
|
||||
* \param buffer A buffer that holds the frame. This parameter may be
|
||||
* \c NULL in which case the buffer will be allocated by the library.
|
||||
* If the application provides the buffer it must be large enough.
|
||||
* \returns a pointer to an empty ::rmff_frame_t structure which can be filled
|
||||
* with the frame contents and its metadata. This frame
|
||||
* must be freed with rmff_release_frame(rmff_frame_t*).
|
||||
*/
|
||||
rmff_frame_t *rmff_allocate_frame(uint32_t size, void *buffer);
|
||||
|
||||
/** \brief Frees all resources associated with a frame.
|
||||
*
|
||||
* If the frame buffer was allocated by the library it will be freed as well.
|
||||
*
|
||||
* \param frame The frame to free.
|
||||
*/
|
||||
void rmff_release_frame(rmff_frame_t *frame);
|
||||
|
||||
/** \brief Sets the contents of the CONT file header.
|
||||
/** \brief Sets the contents of the \link ::rmff_cont_t CONT file header
|
||||
* \endlink.
|
||||
*
|
||||
* Frees the old contents if any and allocates copies of the given
|
||||
* strings. If the CONT header should be written to the file
|
||||
* in rmff_write_headers(rmff_file_t*) then the \c cont_header_found
|
||||
* in rmff_write_headers(rmff_file_t*) then the \a cont_header_present
|
||||
* member must be set to 1.
|
||||
*
|
||||
* \param file The file whose CONT header should be set.
|
||||
@ -313,9 +459,38 @@ void rmff_set_cont_header(rmff_file_t *file, const char *title,
|
||||
const char *author, const char *copyright,
|
||||
const char *comment);
|
||||
|
||||
/** \brief Sets the strings in the \link ::rmff_mdpr_t MDPR track header
|
||||
* \endlink structure.
|
||||
*
|
||||
* Frees the old contents and allocates copies of the given strings.
|
||||
*
|
||||
* \param track The track whose MDPR header should be set.
|
||||
* \param name The track's name.
|
||||
* \param mime_type The MIME type. A video track should have the MIME type
|
||||
* \c video/x-pn-realvideo, and an audio track should have the MIMT type
|
||||
* \c audio/x-pn-realaudio.
|
||||
*/
|
||||
void rmff_set_track_data(rmff_track_t *track, const char *name,
|
||||
const char *mime_type);
|
||||
|
||||
/** \brief Sets the \a track_specific_data member of the \link ::rmff_mdpr_t
|
||||
* MDPR header\endlink structure.
|
||||
*
|
||||
* The \a track_specific_data usually contains a
|
||||
* ::real_video_props_t structure or a ::real_audio_props_t structure.
|
||||
* The existing data, if any, will be freed, and a copy of the memory
|
||||
* \a data points to will be made.
|
||||
*
|
||||
* \param track The track whose MDPR header should be set.
|
||||
* \param data A pointer to the track specific data.
|
||||
* \param size The track specific data's size in bytes.
|
||||
*/
|
||||
void rmff_set_track_specific_data(rmff_track_t *track,
|
||||
const unsigned char *data, uint32_t size);
|
||||
|
||||
/** \brief The error code of the last function call.
|
||||
* Contains the last error code for a function that failed. If a function
|
||||
* succeeded it usually does not reset \c rmff_last_error to \c RMFF_ERR_OK.
|
||||
* succeeded it usually does not reset \a rmff_last_error to \c RMFF_ERR_OK.
|
||||
* This variable can contain one of the \c RMFF_ERR_* constants.
|
||||
*/
|
||||
extern int rmff_last_error;
|
||||
@ -334,6 +509,42 @@ extern const char *rmff_last_error_msg;
|
||||
*/
|
||||
const char *rmff_get_error_str(int code);
|
||||
|
||||
/** \brief Reads a 16bit uint from an address.
|
||||
* The uint is converted from big endian byte order to the machine's byte
|
||||
* order.
|
||||
*
|
||||
* \param buf The address to read from.
|
||||
* \returns The 16bit uint converted to the machine's byte order.
|
||||
*/
|
||||
uint16_t rmff_get_uint16_be(const void *buf);
|
||||
|
||||
/** \brief Reads a 32bit uint from an address.
|
||||
* The uint is converted from big endian byte order to the machine's byte
|
||||
* order.
|
||||
*
|
||||
* \param buf The address to read from.
|
||||
* \returns The 32bit uint converted to the machine's byte order.
|
||||
*/
|
||||
uint32_t rmff_get_uint32_be(const void *buf);
|
||||
|
||||
/** \brief Write a 16bit uint at an address.
|
||||
* The value is converted from the machine's byte order to big endian byte
|
||||
* order.
|
||||
*
|
||||
* \param buf The address to write to.
|
||||
* \param value The value to write.
|
||||
*/
|
||||
void rmff_put_uint16_be(void *buf, uint16_t value);
|
||||
|
||||
/** \brief Write a 32bit uint at an address.
|
||||
* The value is converted from the machine's byte order to big endian byte
|
||||
* order.
|
||||
*
|
||||
* \param buf The address to write to.
|
||||
* \param value The value to write.
|
||||
*/
|
||||
void rmff_put_uint32_be(void *buf, uint32_t value);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
107
librmff/rmff.c
107
librmff/rmff.c
@ -60,8 +60,8 @@ set_error(int error_number,
|
||||
return return_value;
|
||||
}
|
||||
|
||||
static uint16_t
|
||||
get_uint16_be(const void *buf) {
|
||||
uint16_t
|
||||
rmff_get_uint16_be(const void *buf) {
|
||||
uint16_t ret;
|
||||
unsigned char *tmp;
|
||||
|
||||
@ -73,8 +73,8 @@ get_uint16_be(const void *buf) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
get_uint32_be(const void *buf) {
|
||||
uint32_t
|
||||
rmff_get_uint32_be(const void *buf) {
|
||||
uint32_t ret;
|
||||
unsigned char *tmp;
|
||||
|
||||
@ -88,8 +88,8 @@ get_uint32_be(const void *buf) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
put_uint16_be(void *buf,
|
||||
void
|
||||
rmff_put_uin16_be(void *buf,
|
||||
uint16_t value) {
|
||||
unsigned char *tmp;
|
||||
|
||||
@ -99,8 +99,8 @@ put_uint16_be(void *buf,
|
||||
tmp[0] = (value >>= 8) & 0xff;
|
||||
}
|
||||
|
||||
static void
|
||||
put_uint32_be(void *buf,
|
||||
void
|
||||
rmff_put_uin32_be(void *buf,
|
||||
uint32_t value) {
|
||||
unsigned char *tmp;
|
||||
|
||||
@ -115,9 +115,9 @@ put_uint32_be(void *buf,
|
||||
#define read_uint8() file_read_uint8(io, fh)
|
||||
#define read_uint16_be() file_read_uint16_be(io, fh)
|
||||
#define read_uint32_be() file_read_uint32_be(io, fh)
|
||||
#define read_uint16_be_to(addr) put_uint16_be(addr, read_uint16_be())
|
||||
#define read_uint32_be_to(addr) put_uint32_be(addr, read_uint32_be())
|
||||
#define get_fourcc(b) get_uint32_be(b)
|
||||
#define read_uint16_be_to(addr) rmff_put_uin16_be(addr, read_uint16_be())
|
||||
#define read_uint32_be_to(addr) rmff_put_uin32_be(addr, read_uint32_be())
|
||||
#define get_fourcc(b) rmff_get_uint32_be(b)
|
||||
|
||||
static uint8_t
|
||||
file_read_uint8(mb_file_io_t *io,
|
||||
@ -134,7 +134,7 @@ file_read_uint16_be(mb_file_io_t *io,
|
||||
unsigned char tmp[2];
|
||||
|
||||
io->read(fh, tmp, 2);
|
||||
return get_uint16_be(tmp);
|
||||
return rmff_get_uint16_be(tmp);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
@ -143,7 +143,7 @@ file_read_uint32_be(mb_file_io_t *io,
|
||||
unsigned char tmp[4];
|
||||
|
||||
io->read(fh, tmp, 4);
|
||||
return get_uint32_be(tmp);
|
||||
return rmff_get_uint32_be(tmp);
|
||||
}
|
||||
|
||||
void
|
||||
@ -183,24 +183,24 @@ _safestrdup(const char *s,
|
||||
return copy;
|
||||
}
|
||||
|
||||
/* static void * */
|
||||
/* _safememdup(const void *s, */
|
||||
/* size_t size, */
|
||||
/* const char *file, */
|
||||
/* int line) { */
|
||||
/* void *copy; */
|
||||
static void *
|
||||
_safememdup(const void *s,
|
||||
size_t size,
|
||||
const char *file,
|
||||
int line) {
|
||||
void *copy;
|
||||
|
||||
/* if (s == NULL) */
|
||||
/* return NULL; */
|
||||
if (s == NULL)
|
||||
return NULL;
|
||||
|
||||
/* copy = malloc(size); */
|
||||
/* if (copy == NULL) */
|
||||
/* die("safememdup() called from file %s, line %d: malloc() " */
|
||||
/* "returned NULL for a size of %d bytes.", file, line, size); */
|
||||
/* memcpy(copy, s, size); */
|
||||
copy = malloc(size);
|
||||
if (copy == NULL)
|
||||
die("safememdup() called from file %s, line %d: malloc() "
|
||||
"returned NULL for a size of %d bytes.", file, line, size);
|
||||
memcpy(copy, s, size);
|
||||
|
||||
/* return copy; */
|
||||
/* } */
|
||||
return copy;
|
||||
}
|
||||
|
||||
static void *
|
||||
_safemalloc(size_t size,
|
||||
@ -440,7 +440,7 @@ rmff_read_headers(rmff_file_t *file) {
|
||||
track.file = (struct rmff_file_t *)file;
|
||||
mdpr = &track.mdpr_header;
|
||||
read_uint16_be_to(&mdpr->id);
|
||||
track.id = get_uint16_be(&mdpr->id);
|
||||
track.id = rmff_get_uint16_be(&mdpr->id);
|
||||
read_uint32_be_to(&mdpr->max_bit_rate);
|
||||
read_uint32_be_to(&mdpr->avg_bit_rate);
|
||||
read_uint32_be_to(&mdpr->max_packet_size);
|
||||
@ -474,7 +474,7 @@ rmff_read_headers(rmff_file_t *file) {
|
||||
(get_fourcc(&ra4p->fourcc1) ==
|
||||
rmffFOURCC('.', 'r', 'a', 0xfd))) {
|
||||
track.type = RMFF_TRACK_TYPE_AUDIO;
|
||||
if ((get_uint16_be(&ra4p->version1) == 5) &&
|
||||
if ((rmff_get_uint16_be(&ra4p->version1) == 5) &&
|
||||
(size < sizeof(real_audio_v5_props_t)))
|
||||
return set_error(RMFF_ERR_DATA, "RealAudio v5 data indicated but "
|
||||
"data too small", RMFF_ERR_DATA);
|
||||
@ -588,6 +588,24 @@ rmff_read_next_frame(rmff_file_t *file,
|
||||
return frame;
|
||||
}
|
||||
|
||||
rmff_frame_t *
|
||||
rmff_allocate_frame(uint32_t size,
|
||||
void *buffer) {
|
||||
rmff_frame_t *frame;
|
||||
|
||||
if (size == 0)
|
||||
return (rmff_frame_t *)set_error(RMFF_ERR_PARAMETERS, NULL, 0);
|
||||
frame = (rmff_frame_t *)safecalloc(sizeof(rmff_frame_t));
|
||||
if (buffer == NULL) {
|
||||
buffer = safemalloc(size);
|
||||
frame->allocated_by_rmff = 1;
|
||||
}
|
||||
frame->size = size;
|
||||
frame->data = (unsigned char *)buffer;
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
void
|
||||
rmff_release_frame(rmff_frame_t *frame) {
|
||||
if (frame == NULL)
|
||||
@ -615,3 +633,32 @@ rmff_set_cont_header(rmff_file_t *file,
|
||||
file->cont_header.copyright = safestrdup(copyright);
|
||||
file->cont_header.comment = safestrdup(comment);
|
||||
}
|
||||
|
||||
void
|
||||
rmff_set_track_data(rmff_track_t *track,
|
||||
const char *name,
|
||||
const char *mime_type) {
|
||||
if (track == NULL)
|
||||
return;
|
||||
if (name != track->mdpr_header.name) {
|
||||
safefree(track->mdpr_header.name);
|
||||
track->mdpr_header.name = safestrdup(name);
|
||||
}
|
||||
if (mime_type != track->mdpr_header.mime_type) {
|
||||
safefree(track->mdpr_header.mime_type);
|
||||
track->mdpr_header.mime_type = safestrdup(mime_type);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
rmff_set_track_specific_data(rmff_track_t *track,
|
||||
const unsigned char *data,
|
||||
uint32_t size) {
|
||||
if (track == NULL)
|
||||
return;
|
||||
if (data != track->mdpr_header.type_specific_data) {
|
||||
safefree(track->mdpr_header.type_specific_data);
|
||||
track->mdpr_header.type_specific_data =
|
||||
(unsigned char *)safememdup(data, size);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user