mkvtoolnix/librmff/librmff.h

553 lines
19 KiB
C
Raw Normal View History

2004-03-17 19:51:30 +00:00
/*
* librmff.h
*
* Copyright (C) Moritz Bunkus - March 2004
*
* librmff is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1, or (at your option)
* any later version.
*
* librmff is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
/** \file librmff.h
* \brief The RealMedia file format library
* \author Moritz Bunkus <moritz@bunkus.org>
*/
2004-03-18 20:47:24 +00:00
/** \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
*/
2004-03-17 19:51:30 +00:00
#ifndef __RMFF_H
#define __RMFF_H
#if defined(__cplusplus)
extern "C" {
#endif
#include <inttypes.h>
#include <stdio.h>
#include "mb_file_io.h"
2004-03-18 20:47:24 +00:00
/** \brief The global PROP file header.
*
2004-03-17 19:51:30 +00:00
* This header is mandatory for a RealMedia file. It contains statistical
2004-03-18 20:47:24 +00:00
* 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.
2004-03-17 19:51:30 +00:00
*/
typedef struct {
uint32_t max_bit_rate;
uint32_t avg_bit_rate;
uint32_t max_packet_size;
uint32_t avg_packet_size;
uint32_t num_packets;
uint32_t duration;
uint32_t preroll;
uint32_t index_offset;
uint32_t data_offset;
uint16_t num_streams;
uint16_t flags;
} rmff_prop_t;
/** \brief Comments about the file in question.
2004-03-18 20:47:24 +00:00
*
2004-03-17 19:51:30 +00:00
* This structure contains the parsed values of the CONT header. These
* strings must not be modified by the application. The function
2004-03-18 20:47:24 +00:00
* rmff_set_cont_header(rmff_file_t*,const char*,const char*,const char*,const char*)
2004-03-17 19:51:30 +00:00
* must be used instead.
*/
typedef struct {
char *title;
char *author;
char *copyright;
char *comment;
} rmff_cont_t;
2004-03-18 20:47:24 +00:00
/** \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.
*/
2004-03-17 19:51:30 +00:00
typedef struct {
2004-03-18 20:47:24 +00:00
/** \brief The track number. It is unique regarding the file. */
2004-03-17 19:51:30 +00:00
uint16_t id;
2004-03-18 20:47:24 +00:00
/** \brief The maximum bitrate in bit/second.
*
* When creating a file this value will
* be updated automatically by the library. */
2004-03-17 19:51:30 +00:00
uint32_t max_bit_rate;
2004-03-18 20:47:24 +00:00
/** \brief The average bitrate in bit/second.
*
* When creating a file this value will
* be updated automatically by the library. */
2004-03-17 19:51:30 +00:00
uint32_t avg_bit_rate;
2004-03-18 20:47:24 +00:00
/** \brief The maximum packet size in bytes.
*
* When creating a file this value will
* be updated automatically by the library. */
2004-03-17 19:51:30 +00:00
uint32_t max_packet_size;
2004-03-18 20:47:24 +00:00
/** \brief The average packet size in bytes.
*
* When creating a file this value will
* be updated automatically by the library. */
2004-03-17 19:51:30 +00:00
uint32_t avg_packet_size;
uint32_t start_time;
uint32_t preroll;
uint32_t duration;
2004-03-18 20:47:24 +00:00
/** \brief The track's name.
*
* Use the rmff_set_track_data(rmff_track_t*,const char*,const char*)
* function for setting it. */
2004-03-17 19:51:30 +00:00
char *name;
2004-03-18 20:47:24 +00:00
/** \brief The track's MIME type.
*
* Use the rmff_set_track_data(rmff_track_t*,const char*,const char*)
* function for setting it. */
2004-03-17 19:51:30 +00:00
char *mime_type;
2004-03-18 20:47:24 +00:00
/** \brief The size of the track specific data in bytes. */
2004-03-17 19:51:30 +00:00
uint32_t type_specific_size;
2004-03-18 20:47:24 +00:00
/** \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. */
2004-03-17 19:51:30 +00:00
unsigned char *type_specific_data;
} rmff_mdpr_t;
typedef struct __attribute__((__packed__)) real_video_props_t {
uint32_t size;
uint32_t fourcc1;
uint32_t fourcc2;
uint16_t width;
uint16_t height;
uint16_t bpp;
uint32_t unknown1;
uint32_t fps;
uint32_t type1;
uint32_t type2;
} real_video_props_t;
typedef struct __attribute__((__packed__)) real_audio_v4_props_t {
uint32_t fourcc1; /* '.', 'r', 'a', 0xfd */
uint16_t version1; /* 4 or 5 */
uint16_t unknown1; /* 00 00 */
uint32_t fourcc2; /* .ra4 or .ra5 */
uint32_t unknown2; /* ??? */
uint16_t version2; /* 4 or 5 */
uint32_t header_size; /* == 0x4e */
uint16_t flavor; /* codec flavor id */
uint32_t coded_frame_size; /* coded frame size */
uint32_t unknown3; /* big number */
uint32_t unknown4; /* bigger number */
uint32_t unknown5; /* yet another number */
uint16_t sub_packet_h;
uint16_t frame_size;
uint16_t sub_packet_size;
uint16_t unknown6; /* 00 00 */
uint16_t sample_rate;
uint16_t unknown8; /* 0 */
uint16_t sample_size;
uint16_t channels;
} real_audio_v4_props_t;
typedef struct __attribute__((__packed__)) real_audio_v5_props_t {
uint32_t fourcc1; /* '.', 'r', 'a', 0xfd */
uint16_t version1; /* 4 or 5 */
uint16_t unknown1; /* 00 00 */
uint32_t fourcc2; /* .ra4 or .ra5 */
uint32_t unknown2; /* ??? */
uint16_t version2; /* 4 or 5 */
uint32_t header_size; /* == 0x4e */
uint16_t flavor; /* codec flavor id */
uint32_t coded_frame_size; /* coded frame size */
uint32_t unknown3; /* big number */
uint32_t unknown4; /* bigger number */
uint32_t unknown5; /* yet another number */
uint16_t sub_packet_h;
uint16_t frame_size;
uint16_t sub_packet_size;
uint16_t unknown6; /* 00 00 */
uint8_t unknown7[6]; /* 0, srate, 0 */
uint16_t sample_rate;
uint16_t unknown8; /* 0 */
uint16_t sample_size;
uint16_t channels;
uint32_t genr; /* "genr" */
uint32_t fourcc3; /* fourcc */
} real_audio_v5_props_t;
typedef struct rmff_frame_t {
unsigned char *data;
2004-03-17 19:51:30 +00:00
uint32_t size;
int allocated_by_rmff;
uint16_t id;
uint32_t timecode;
uint8_t reserved;
uint8_t flags;
} rmff_frame_t;
/** \brief Unknown track type. */
#define RMFF_TRACK_TYPE_UNKNOWN 0
/** \brief The track contains audio data. */
#define RMFF_TRACK_TYPE_AUDIO 1
/** \brief The track contains video data. */
#define RMFF_TRACK_TYPE_VIDEO 2
2004-03-18 20:47:24 +00:00
struct rmff_file_t;
2004-03-17 19:51:30 +00:00
typedef struct rmff_track_t {
2004-03-17 19:51:30 +00:00
uint32_t id;
int type;
rmff_mdpr_t mdpr_header;
int is_big_endian;
struct rmff_file_t *file;
} rmff_track_t;
typedef struct rmff_file_t {
2004-03-17 19:51:30 +00:00
mb_file_io_t *io;
void *handle;
char *name;
2004-03-18 19:01:35 +00:00
int open_mode;
2004-03-17 19:51:30 +00:00
int64_t size;
int headers_read;
rmff_prop_t prop_header;
rmff_cont_t cont_header;
2004-03-18 19:01:35 +00:00
int cont_header_present;
2004-03-17 19:51:30 +00:00
int64_t first_data_header_offset;
int64_t next_data_header_offset;
uint32_t num_packets_in_chunk;
uint32_t num_packets_read;
int is_big_endian;
rmff_track_t *tracks;
int num_tracks;
} rmff_file_t;
/** \brief No error has occured. */
#define RMFF_ERR_OK 0
/** \brief The file is not a valid RealMedia file. */
#define RMFF_ERR_NOT_RMFF -1
/** \brief The structures/data read from the file were invalid. */
#define RMFF_ERR_DATA -2
/** \brief The end of the file has been reached. */
#define RMFF_ERR_EOF -3
/** \brief An error occured during file I/O. */
#define RMFF_ERR_IO -4
/** \brief The parameters were invalid. */
#define RMFF_ERR_PARAMETERS -5
/** \brief An error has occured for which \c errno should be consulted. */
#define RMFF_ERR_CHECK_ERRNO -6
2004-03-18 20:47:24 +00:00
/** \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))
2004-03-17 19:51:30 +00:00
#define RMFF_OPEN_MODE_READING 0
#define RMFF_OPEN_MODE_WRITING 1
2004-03-17 19:51:30 +00:00
/** \brief Opens a RealMedia file for reading or writing.
2004-03-18 20:47:24 +00:00
*
2004-03-17 19:51:30 +00:00
* 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
* current operating system.
*
* \param path the name of the file that should be opened
* \param mode either ::RMFF_OPEN_MODE_READING or ::RMFF_OPEN_MODE_WRITING
2004-03-18 20:47:24 +00:00
* \returns a pointer to ::rmff_file_t structure or \c NULL if an error
2004-03-17 19:51:30 +00:00
* 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.
2004-03-18 20:47:24 +00:00
*
2004-03-17 19:51:30 +00:00
* 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.
2004-03-18 20:47:24 +00:00
* This function uses I/O functions provided by the \a io parameter.
2004-03-17 19:51:30 +00:00
*
* \param path the name of the file that should be opened
* \param mode either ::RMFF_OPEN_MODE_READING or ::RMFF_OPEN_MODE_WRITING
* \param io a set of I/O functions
* \returns a pointer to a 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
*/
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.
2004-03-18 20:47:24 +00:00
*
2004-03-17 19:51:30 +00:00
* Closes the file and releases all resources associated with it, including
2004-03-18 20:47:24 +00:00
* the ::rmff_file_t structure. If the file was open for writing then
2004-03-17 19:51:30 +00:00
* rmff_write_headers() should be called prior to closing the file as
* \c rmff_close_file does not fix the headers itself.
*
* \param file The file to close.
*/
void rmff_close_file(rmff_file_t *file);
/** \brief Reads the file and track headers.
2004-03-18 20:47:24 +00:00
*
2004-03-17 19:51:30 +00:00
* 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.
*
* \param file The file to read the headers from.
* \returns ::RMFF_ERR_OK on success and one of the other \c RMFF_ERR_*
* constants on error.
*/
int rmff_read_headers(rmff_file_t *file);
/** \brief Retrieves the size of the next frame.
2004-03-18 19:01:35 +00:00
*
2004-03-17 19:51:30 +00:00
* \param file The file to read from.
* \returns the size of the following frame or one of the \c RMFF_ERR_*
* constants on error.
*/
int rmff_get_next_frame_size(rmff_file_t *file);
/** \brief Reads the next frame from the file.
2004-03-18 20:47:24 +00:00
*
2004-03-17 19:51:30 +00:00
* The frame must be released by rmff_release_frame(rmff_frame_t*).
2004-03-18 19:01:35 +00:00
*
2004-03-17 19:51:30 +00:00
* \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.
2004-03-18 20:47:24 +00:00
* The function rmff_get_next_frame_size(rmff_file_t*) can be used in this
* case.
2004-03-17 19:51:30 +00:00
* \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);
2004-03-18 20:47:24 +00:00
/** \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);
2004-03-17 19:51:30 +00:00
/** \brief Frees all resources associated with a frame.
2004-03-18 20:47:24 +00:00
*
2004-03-17 19:51:30 +00:00
* If the frame buffer was allocated by the library it will be freed as well.
2004-03-18 19:01:35 +00:00
*
2004-03-17 19:51:30 +00:00
* \param frame The frame to free.
*/
void rmff_release_frame(rmff_frame_t *frame);
2004-03-18 20:47:24 +00:00
/** \brief Sets the contents of the \link ::rmff_cont_t CONT file header
* \endlink.
*
2004-03-18 19:01:35 +00:00
* Frees the old contents if any and allocates copies of the given
* strings. If the CONT header should be written to the file
2004-03-18 20:47:24 +00:00
* in rmff_write_headers(rmff_file_t*) then the \a cont_header_present
2004-03-18 19:01:35 +00:00
* member must be set to 1.
*
* \param file The file whose CONT header should be set.
* \param title The file's title, e.g. "Muriel's Wedding"
* \param author The file's author, e.g. "P.J. Hogan"
* \param copyright The copyright assigned to the file.
* \param comment A free-style comment.
*/
void rmff_set_cont_header(rmff_file_t *file, const char *title,
const char *author, const char *copyright,
const char *comment);
2004-03-17 19:51:30 +00:00
2004-03-18 20:47:24 +00:00
/** \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);
2004-03-17 19:51:30 +00:00
/** \brief The error code of the last function call.
* Contains the last error code for a function that failed. If a function
2004-03-18 20:47:24 +00:00
* succeeded it usually does not reset \a rmff_last_error to \c RMFF_ERR_OK.
2004-03-17 19:51:30 +00:00
* This variable can contain one of the \c RMFF_ERR_* constants.
*/
extern int rmff_last_error;
/** \brief The error message of the last function call.
* Contains the last error message for a function that failed. If a function
* succeeded it usually does not reset \c rmff_last_error_msg to \c NULL.
*/
extern const char *rmff_last_error_msg;
/** \brief Map an error code to an error message.
* Returns the error message that corresponds to the error code.
* \param code the error code which must be one of the \c RMFF_ERR_* macros.
* \returns the error message or "Unknown error" for unknown error codes,
* but never \c NULL.
*/
const char *rmff_get_error_str(int code);
2004-03-18 20:47:24 +00:00
/** \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);
2004-03-17 19:51:30 +00:00
#if defined(__cplusplus)
}
#endif
#endif /* __RMFF_H */