You can find a description of the RealMedia file format at http://www.pcisys.net/~melanson/codecs/rmff.htm
Example:
rmff_file_t *file; rmff_frame_t *frame; file = rmff_open_file("sample_file.rm", RMFF_OPEN_MODE_READING); 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. // 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);
Creating a new file involves the following step in this particular order:
RMFF_OPEN_MODR_WRITING
,Please note that the error handling is not shown in the following example:
rmff_file_t *file; rmff_track_t *track; rmff_frame_t *frame; file = rmff_open_file("new_file.rm", RMFF_OPEN_MODE_WRITING); track = rmff_add_track(file, 1); // Also create an index for this track. // The track types etc are stored in the ::rmff_mdpr_t#type_specific_data // It usually contains a ::real_audio_v4_props_t, ::real_audio_v5_props_t // or ::real_video_props_t structures which have to be set by the // calling application. // After setting the structures: rmff_write_headers(file); while (!done) { // Generate frames. ... frame = rmff_allocate_frame(size, NULL); rmff_write_frame(track, frame); rmff_release_frame(frame); } rmff_write_index(file); rmff_fix_headers(file); rmff_close_file(file);
app_data
pointers.
The app_data
members in ::rmff_file_t and ::rmff_track_t are never touched by librmff and can be used by the application to store its own data.
The functions rmff_read_next_frame, rmff_release_frame and rmff_allocate_frame allow the application to provide its own buffers for storing the frame contents. librmff will not copy this memory further. It will read directly into the buffer or write directly from the buffer into the file.
Example:
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); }
librmff can make the developper's life easier because it provides the function rmff_write_packed_video_frame that will split up such an assembled packet into all the sub packets and write those automatically, and two functions that assemble sub packets into such a packed frame (rmff_assemble_packed_video_frame and rmff_get_packed_video_frame).
AA = 00
and AA = 10
:AABBBBBB BCCCCCCC DEFFFFFF FFFFFFFF (GGGGGGGG GGGGGGGG) HIJJJJJJ JJJJJJJJ (KKKKKKKK KKKKKKKK) LLLLLLLL
AA = 01
:AABBBBBB BCCCCCCC
AA = 11
:AABBBBBB DEFFFFFF FFFFFFFF (GGGGGGGG GGGGGGGG) HIJJJJJJ JJJJJJJJ (KKKKKKKK KKKKKKKK) LLLLLLLL
A
, two bits: Sub packet type indicator00
partial frame01
whole frame. If this is the case then only the bits A, B
and C
are present. In all the other cases the other bits are present as well.10
last partial frame11
multiple framesB
, seven bits: number of sub packets in the complete frameC
, seven bits: current sub packet's sequence number starting at 1D
, one bit: unknownE
, one bit: If set the G
bits/bytes are not present.F
, 14 bits: The complete frame's length in bytes. If E
is NOT set then the total length is (F << 16) | G
, otherwise G
is not present and the total length is just F
.H
, one bit, unknownI
, one bit: If set the L
bits/bytes are not present.J
, 14 bits: The current packet's offset in bytes. If J
is NOT set then the offset is (J << 16) | K
, otherwise K
is not present and the offset is just J
. Note that if AA
is 10 then the offset is to be interpreted from the end of the of the complete frame. In this case it is equal to the current sub packet's length.L
, 8 bits: The current frame's sequence number / frame number 255. Can be used for detecting frame boundaries if the sub packaging has failed or the stream is broken.rmff_frame_t *raw_frame, *packed_frame; rmff_track_t *track; int result; // Open the file, check the tracks. while ((raw_frame = rmff_read_next_frame(file, NULL)) != NULL) { track = rmff_find_track_with_id(file, raw_frame->id); if (track->type != RMFF_TRACK_TYPE_VIDEO) { // Handle audio etc. } else { if ((result = rmff_assemble_packed_video_frame(track, raw_frame)) < 0) { // Handle the error. } else { while ((packed_frame = rmff_get_packed_video_frame(track)) != NULL) { // Do something with the assembled frame and release it afterwards. rmff_release_frame(packed_frame); } } } rmff_release_frame(raw_frame); }