Mercurial > mplayer.hg
changeset 19057:7c30d49e7850
rename mpcf.txt to nut.txt
author | michael |
---|---|
date | Thu, 13 Jul 2006 10:29:21 +0000 |
parents | 36f993b7f91d |
children | f9280c15ac82 |
files | DOCS/tech/mpcf.txt DOCS/tech/nut.txt |
diffstat | 2 files changed, 927 insertions(+), 927 deletions(-) [+] |
line wrap: on
line diff
--- a/DOCS/tech/mpcf.txt Thu Jul 13 10:26:33 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,927 +0,0 @@ -================================== -NUT Open Container Format 20060713 -================================== - - - -Intro: -====== - -Features / goals: - (supported by the format, not necessarily by a specific implementation) - -Simple - use the same encoding for nearly all fields - simple decoding, so slow CPUs (and embedded systems) can handle it - -Extendible - no limit for the possible values of all fields (using universal vlc) - allow adding of new headers in the future - allow adding more fields at the end of headers - -Compact - ~0.2% overhead, for normal bitrates - index is <100kb per hour - a usual header for a file is about 100 bytes (audio + video headers together) - a packet header is about ~1-5 bytes - -Error resistant - seeking / playback without an index - headers & index can be repeated - damaged files can be played back with minimal data loss and fast - resync times - -The spec is frozen. All files following spec will be compatible unless the -spec is unfrozen. - - -Definitions: -============ - -MUST the specific part must be done to conform to this standard -SHOULD it is recommended to be done that way, but not strictly required - - - -Syntax: -======= - -Since NUT heavily uses variable length fields, the simplest way to describe it -is using a pseudocode approach. - - - -Conventions: -============ - -The data types have a name, used in the bitstream syntax description, a short -text description and a pseudocode (functional) definition, optional notes may -follow: - -name (text description) - functional definition - [Optional notes] - -The bitstream syntax elements have a tagname and a functional definition, they -are presented in a bottom up approach, again optional notes may follow and -are reproduced in the tag description: - -name: (optional note) - functional definition - [Optional notes] - -The in-depth tag description follows the bitstream syntax. -The functional definition has a C-like syntax. - - - -Type definitions: -================= - -f(n) (n fixed bits in big-endian order) -u(n) (unsigned number encoded in n bits in MSB-first order) - -v (variable length value, unsigned) - value=0 - do{ - more_data u(1) - data u(7) - value= 128*value + data - }while(more_data) - -s (variable length value, signed) - temp v - temp++ - if(temp&1) value= -(temp>>1) - else value= (temp>>1) - -b (binary data or string, to be use in vb, see below) - for(i=0; i<length; i++){ - data[i] u(8) - } - [Note: strings MUST be encoded in UTF-8] - [Note: the character NUL (U+0000) is not legal within - or at the end of a string.] - -vb (variable length binary data or string) - length v - value b - -t (v coded universal timestamp) - tmp v - id= tmp % time_base_count - value= (tmp / time_base_count) * time_base[id] - - -Bitstream syntax: -================= - -Common elements: ----------------- - -reserved_bytes: - for(i=0; i<forward_ptr - length_of_non_reserved; i++) - reserved u(8) - [a demuxer MUST ignore any reserved bytes - a muxer MUST NOT write any reserved bytes, as this would make it - impossible to add new fields at the end of packets in the future - in a compatible way] - -packet_header - startcode f(64) - forward_ptr v - if(forward_ptr > 4096) - header_checksum u(32) - -packet_footer - reserved_bytes - checksum u(32) - [Note: in index packet, reserved_bytes comes before index_ptr] - -reserved_headers - while(next_byte == 'N' && next_code != main_startcode - && next_code != stream_startcode - && next_code != info_startcode - && next_code != index_startcode - && next_code != syncpoint_startcode){ - packet_header - packet_footer - } - - Headers: - -main header: - version v - stream_count v - max_distance v - time_base_count v - for(i=0; i<time_base_count; i++) - time_base_nom v - time_base_denom v - time_base[i]= time_base_nom/time_base_denom - tmp_pts=0 - tmp_mul=1 - tmp_stream=0 - for(i=0; i<256; ){ - tmp_flag v - tmp_fields v - if(tmp_fields>0) tmp_pts s - if(tmp_fields>1) tmp_mul v - if(tmp_fields>2) tmp_stream v - if(tmp_fields>3) tmp_size v - else tmp_size=0 - if(tmp_fields>4) tmp_res v - else tmp_res=0 - if(tmp_fields>5) count v - else count= tmp_mul - tmp_size - for(j=6; j<tmp_fields; j++){ - tmp_reserved[i] v - } - for(j=0; j<count && i<256; j++, i++){ - if (i == 'N') { - flags[i]= FLAG_INVALID; - j--; - continue; - } - flags[i]= tmp_flag; - stream_id[i]= tmp_stream; - data_size_mul[i]= tmp_mul; - data_size_lsb[i]= tmp_size + j; - pts_delta[i]= tmp_pts; - reserved_count[i]= tmp_res; - } - } - -stream_header: - stream_id v - stream_class v - fourcc vb - time_base_id v - msb_pts_shift v - max_pts_distance v - decode_delay v - stream_flags v - codec_specific_data vb - if(stream_class == video){ - width v - height v - sample_width v - sample_height v - colorspace_type v - }else if(stream_class == audio){ - samplerate_nom v - samplerate_denom v - channel_count v - } - - Basic Packets: - -frame: - frame_code f(8) - frame_flags= flags[frame_code] - if(frame_flags&FLAG_CODED){ - coded_flags v - frame_flags ^= coded_flags - } - if(frame_flags&FLAG_STREAM_ID){ - stream_id v - } - if(frame_flags&FLAG_CODED_PTS){ - coded_pts v - } - if(frame_flags&FLAG_SIZE_MSB){ - data_size_msb v - } - if(frame_flags&FLAG_RESERVED) - reserved_count[frame_code] v - for(i=0; i<reserved_count[frame_code]; i++) - reserved v - if(frame_flags&FLAG_CHECKSUM){ - checksum u(32) - } - data - -index: - max_pts t - syncpoints v - for(i=0; i<syncpoints; i++){ - syncpoint_pos_div16 v - } - for(i=0; i<stream_count; i++){ - last_pts= -1 - for(j=0; j<syncpoints; ){ - x v - type= x & 1 - x>>=1 - n=j - if(type){ - flag= x & 1 - x>>=1 - while(x--) - has_keyframe[n++][i]=flag - has_keyframe[n++][i]=!flag; - }else{ - while(x != 1){ - has_keyframe[n++][i]=x&1; - x>>=1; - } - } - for(; j<n && j<syncpoints; j++){ - if (!has_keyframe[j][i]) continue - A v - if(!A){ - A v - B v - eor_pts[j][i] = last_pts + A + B - }else - B=0 - keyframe_pts[j][i] = last_pts + A - last_pts += A + B - } - } - } - reserved_bytes - index_ptr u(64) - -info_packet: - stream_id_plus1 v - chapter_id v - chapter_start t - chapter_len v - count v - for(i=0; i<count; i++){ - name vb - value s - if (value==-1){ - type= "UTF-8" - value vb - }else if (value==-2){ - type vb - value vb - }else if (value==-3){ - type= "s" - value s - }else if (value==-4){ - type= "t" - value t - }else if (value<-4){ - type= "r" - value.den= -value-4 - value.num s - }else{ - type= "v" - } - } - -syncpoint: - global_key_pts t - back_ptr_div16 v - - Complete definition: - -file: - file_id_string - while(!eof){ - if(next_byte == 'N'){ - packet_header - switch(startcode){ - case main_startcode: main_header; break; - case stream_startcode:stream_header; break; - case info_startcode: info_packet; break; - case index_startcode: index; break; - case syncpoint_startcode: syncpoint; break; - } - packet_footer - }else - frame - } - -the structure of a undamaged file should look like the following, but -demuxers should be flexible and be able to deal with damaged headers so the -above is a better loop in practice (not to mention its simpler) -note, demuxers MUST be able to deal with new and unknown headers - -file: - file_id_string - while(!eof){ - packet_header, main_header, packet_footer - reserved_headers - for(i=0; i<stream_count; i++){ - packet_header, stream_header, packet_footer - reserved_headers - } - while(next_code == info_startcode){ - packet_header, info_packet, packet_footer - reserved_headers - } - if(next_code == index_startcode){ - packet_header, index_packet, packet_footer - } - if (!eof) while(next_code != main_startcode){ - if(next_code == syncpoint_startcode){ - packet_header, syncpoint, packet_footer - } - frame - reserved_headers - } - } - - -Tag description: ----------------- - -file_id_string - "nut/multimedia container\0" - -*_startcode - all startcodes start with 'N' - -main_startcode - 0x7A561F5F04ADULL + (((uint64_t)('N'<<8) + 'M')<<48) - -stream_starcode - 0x11405BF2F9DBULL + (((uint64_t)('N'<<8) + 'S')<<48) - -syncpoint_startcode - 0xE4ADEECA4569ULL + (((uint64_t)('N'<<8) + 'K')<<48) - -index_startcode - 0xDD672F23E64EULL + (((uint64_t)('N'<<8) + 'X')<<48) - -info_startcode - 0xAB68B596BA78ULL + (((uint64_t)('N'<<8) + 'I')<<48) - -version - NUT version. The current value is 3. All lower values are pre-freeze - -forward_ptr - size of the packet data (exactly the distance from the first byte - after the packet_header to the first byte of the next packet) - -max_distance - max distance between startcodes. If p1 and p2 are the byte - positions of the first byte of two consecutive startcodes, then - p2-p1 MUST be less than or equal to max_distance unless the entire - span from p1 to p2 comprises a single packet or a syncpoint - followed by a single frame. This imposition places efficient upper - bounds on seek operations and allows for the detection of damaged - frame headers, should a chain of frame headers pass max_distance - without encountering any startcode. - - syncpoints SHOULD be placed immediately before a keyframe if the - previous frame of the same stream was a non-keyframe, unless such - non-keyframe - keyframe transitions are very frequent - - SHOULD be set to <=32768 - if the stored value is >65536 then max_distance MUST be set to 65536 - - This is also half the max frame size without a checksum after the - frameheader. - - -max_pts_distance - max absoloute difference of pts of new frame from last_pts in the - timebase of the stream, without a checksum after the frameheader. - A frame header MUST include a checksum if abs(pts-last_pts) is - strictly greater than max_pts_distance. - Note that last_pts is not necessarily the pts of the last frame - on the same stream, as it is altered by syncpoint timestamps. - SHOULD NOT be higher than 1/timebase - -stream_id - Stream identifier - stream_id MUST be < stream_count - -stream_class - 0 video - 1 audio - 2 subtiles - 3 userdata - Note: the remaining values are reserved and MUST NOT be used - a demuxer MUST ignore streams with reserved classes - -fourcc - identification for the codec - example: "H264" - MUST contain 2 or 4 bytes, note, this might be increased in the future - if needed - the id values used are the same as in avi, so if a codec uses a specific - fourcc in avi then the same fourcc MUST be used here - -time_base_nom / time_base_denom = time_base - the length of a timer tick in seconds, this MUST be equal to the 1/fps - if FLAG_FIXED_FPS is set - time_base_nom and time_base_denom MUST NOT be 0 - time_base_nom and time_base_denom MUST be relatively prime - time_base_denom MUST be < 2^31 - examples: - fps time_base_nom time_base_denom - 30 1 30 - 29.97 1001 30000 - 23.976 1001 24000 - There MUST NOT be 2 identical timebases in a file. - There SHOULD NOT be more timebases than streams. - -time_base_id - id to time_base table - -convert_ts - To switch from 2 different timebases, the following calculation is - defined: - - ln = from_time_base_nom*to_time_base_denom - sn = from_timestamp - d1 = from_time_base_denom - d2 = to_time_base_nom - timestamp = (ln/d1*sn + ln%d1*sn/d1)/d2 - Note: this calculation MUST be done with unsigned 64 bit integers, and - is equivalent to (ln*sn)/(d1*d2) but this would require a 96bit integer - -compare_ts - Compares timestamps from 2 different timebases, - if a is before b then compare_ts(a, b) = -1 - if a is after b then compare_ts(a, b) = 1 - else compare_ts(a, b) = 0 - - Care must be taken that this is done exactly with no rounding errors, - simply casting to float or double and doing the obvious - a*timebase > b*timebase is not compliant or correct, neither is the - same with integers, and - a*a_timebase.num*b_timebase.den > b*b_timebase.num*a_timebase.den - will overflow. One possible implementation which shouldn't overflow - within the range of legal timestamps and timebases is: - - if (convert_ts(a, a_timebase, b_timebase) < b) return -1; - if (convert_ts(b, b_timebase, a_timebase) < a) return 1; - return 0; - -msb_pts_shift - amount of bits in lsb_pts - MUST be <16 - -decode_delay - maximum time between input and output for a codec, used to generate - dts from pts - is set to 0 for streams without B-frames, and set to 1 for streams with - B-frames, may be larger for future codecs - decode_delay MUST NOT be set higher than necessary for a codec. - -stream_flags - Bit Name Description - 1 FLAG_FIXED_FPS indicates that the fps is fixed - -codec_specific_data - private global data for a codec (could be huffman tables or ...) - -frame_code - the meaning of this byte is stored in the main header - the value 78 ('N') is forbidden to ensure that the byte is always - different from the first byte of any startcode - a muxer SHOULD mark 0x00 and 0xFF as invalid to improve error - detection - -flags[frame_code], frame_flags - Bit Name Description - 1 FLAG_KEY if set, frame is keyframe - 2 FLAG_EOR if set, stream has no relevance on - presentation. (EOR) - 8 FLAG_CODED_PTS if set, coded_pts is in the frame header - 16 FLAG_STREAM_ID if set, stream_id is coded in the frame header - 32 FLAG_SIZE_MSB if set, data_size_msb is at frame header, - otherwise data_size_msb is 0 - 64 FLAG_CHECKSUM if set then the frame header contains a checksum - 128 FLAG_RESERVED if set, reserved_count is coded in the frame header - 4096 FLAG_CODED if set, coded_flags are stored in the frame header. - 8192 FLAG_INVALID if set, frame_code is invalid. - - EOR frames MUST be zero-length and must be set keyframe. - All streams SHOULD end with EOR, where the pts of the EOR indicates the - end presentation time of the final frame. - An EOR set stream is unset by the first content frames. - EOR can only be unset in streams with zero decode_delay . - FLAG_CHECKSUM MUST be set if the frame's data_size is strictly greater than - 2*max_distance or the difference abs(pts-last_pts) is strictly greater than - max_pts_distance (where pts represents this frame's pts and last_pts is - defined as below). - -stream_id[frame_code] - MUST be <250 - -data_size_mul[frame_code] - MUST be <16384 - -data_size_lsb[frame_code] - MUST be <16384 - -pts_delta[frame_code] - MUST be <16384 and >-16384 - -reserved_count[frame_code] - MUST be <256 - -data_size - data_size= data_size_lsb + data_size_msb*data_size_mul; - -coded_pts - if coded_pts < (1<<msb_pts_shift) then it is an lsb - pts, otherwise it is a full pts + (1<<msb_pts_shift) - lsb pts is converted to a full pts by: - mask = (1<<msb_pts_shift)-1; - delta = last_pts - mask/2 - pts = ((pts_lsb-delta)&mask) + delta - -lsb_pts - least significant bits of the pts in time_base precision - Example: IBBP display order - keyframe pts=0 -> pts=0 - frame lsb_pts=3 -> pts=3 - frame lsb_pts=1 -> pts=1 - frame lsb_pts=2 -> pts=2 - ... - keyframe msb_pts=257 -> pts=257 - frame lsb_pts=255 -> pts=255 - frame lsb_pts=0 -> pts=256 - frame lsb_pts=4 -> pts=260 - frame lsb_pts=2 -> pts=258 - frame lsb_pts=3 -> pts=259 - all pts's of keyframes of a single stream MUST be monotone - -dts - dts is calculated by using a decode_delay+1 sized buffer for each - stream, into which the current pts is inserted and the element with - the smallest value is removed, this is then the current dts - this buffer is initalized with decode_delay -1 elements - - Pts of all frames in all streams MUST be bigger or equal to dts of all - previous frames in all streams, compared in common timebase. (EOR - frames are NOT exempt from this rule) - -width/height - MUST be set to the coded width/height, MUST NOT be 0 - -sample_width/sample_height (aspect ratio) - sample_width is the horizontal distance between samples - sample_width and sample_height MUST be relatively prime if not zero - both MUST be 0 if unknown otherwise both MUST be non zero - -colorspace_type - 0 unknown - 1 ITU Rec 624 / ITU Rec 601 Y range: 16..235 Cb/Cr range: 16..240 - 2 ITU Rec 709 Y range: 16..235 Cb/Cr range: 16..240 - 17 ITU Rec 624 / ITU Rec 601 Y range: 0..255 Cb/Cr range: 0..255 - 18 ITU Rec 709 Y range: 0..255 Cb/Cr range: 0..255 - -samplerate_nom / samplerate_denom = samplerate - the number of samples per second, MUST NOT be 0 - -crc32 checksum - Generator polynomial is 0x104C11DB7. Starting value is zero. - -checksum - crc32 checksum - checksum is calculated for the area pointed to by forward_ptr not - including the checksum itself (from first byte after the - packet_header until last byte before the checksum). - for frame headers the checksum contains the framecode byte and all - following bytes upto the checksum itself - -header_checksum - checksum over the startcode and forward pointer - -Syncpoint tags: ---------------- - -back_ptr_div16 - back_ptr = back_ptr_div16 * 16 + 15 - back_ptr must point to a position within 16 bytes of a syncpoint - startcode. This syncpoint MUST be the closest syncpoint such that at - least one keyframe with a pts lower or equal to the original syncpoint's - global_key_pts for all streams lies between it and the current syncpoint. - - A stream where EOR is set is to be ignored for back_ptr. - -global_key_pts - After a syncpoint, last_pts of each stream is to be set to: - last_pts[i] = convert_ts(global_key_pts, time_base[id], time_base[i]) - - global_key_pts MUST be bigger or equal to dts of all past frames across - all streams, and smaller or equal to pts of all future frames. - -Index tags: ------------ - -max_pts - The highest pts in the entire file - -syncpoint_pos_div16 - offset from begginning of file to up to 15 bytes before the syncpoint - referred to in this index entry. Relative to position of last - syncpoint. - -has_keyframe - indicates whether this stream has a keyframe between this syncpoint and - the last syncpoint. - -keyframe_pts - The pts of the first keyframe for this stream in the region between the - 2 syncpoints, in the stream's timebase. (EOR frames are also keyframes) - -eor_pts - Coded only if EOR is set at the position of the syncpoint. The pts of - that EOR. EOR is unset by the first keyframe after it. - -index_ptr - Length in bytes of the entire index, from the first byte of the - startcode until the last byte of the checksum. - Note: A demuxer can use this to find the index when it is written at - EOF, as index_ptr will always be 12 bytes before the end of file if - there is an index at all. - - -Info tags: ----------- - -stream_id_plus1 - Stream this info packet applies to. If zero, packet applies to whole - file. - -chapter_id - Id of chapter this packet applies to. If zero, packet applies to whole - file. Positive chapter_id's are real chapters and MUST NOT overlap. - Negative chapter_id indicate a sub region of file and not a real - chapter. chapter_id MUST be unique to the region it represents. - chapter_id n MUST not be used unless there are at least n chapters in the - file - -chapter_start - timestamp of start of chapter - -chapter_len - Length of chapter in same timebase of chapter_start. - -type - for example: "UTF8" -> string or "JPEG" -> JPEG image - "v" -> unsigned integer - "s" -> signed integer - "r" -> rational - Note: nonstandard fields should be prefixed by "X-" - Note: MUST be less than 6 byte long (might be increased to 64 later) - -info packet types - the name of the info entry, valid names are - "Author" - "Description" - "Copyright" - "Encoder" - the name & version of the software used for encoding - "Title" - "Cover" (allowed types are "PNG" and "JPEG") - image of the (CD, DVD, VHS, ..) cover (preferably PNG or JPEG) - "Source" - "DVD", "VCD", "CD", "MD", "FM radio", "VHS", "TV", "LD" - Optional: appended PAL, NTSC, SECAM, ... in parentheses - "SourceContainer" - "nut", "mkv", "mov", "avi", "ogg", "rm", "mpeg-ps", "mpeg-ts", "raw" - "SourceCodecTag" - the source codec id like a fourcc which was used to store a specific - stream in its SourceContainer - "CaptureDevice" - "BT878", "BT848", "webcam", ... (more exact names are fine too) - "CreationTime" - "2003-01-20 20:13:15Z", ... - (ISO 8601 format, see http://www.cl.cam.ac.uk/~mgk25/iso-time.html) - Note: do not forget the timezone - "Keywords" - "Language" - ISO 639 and ISO 3166 for language/country code - something like "eng" (US english), can be 0 if unknown - and "multi" if several languages - see http://www.loc.gov/standards/iso639-2/englangn.html - and http://www.din.de/gremien/nas/nabd/iso3166ma/codlstp1/en_listp1.html - the language code - "Disposition" - "original", "dub" (translated), "comment", "lyrics", "karaoke" - Note: if someone needs some others, please tell us about them, so we - can add them to the official standard (if they are sane) - Note: nonstandard fields should be prefixed by "X-" - Note: names of fields SHOULD be in English if a word with the same - meaning exists in English - Note: MUST be less than 64 bytes long - -value - value of this name/type pair - -stuffing - 0x80 can be placed in front of any type v entry for stuffing purposes - except the forward_ptr and all fields in the frame header where a - maximum of 8 stuffing bytes per field are allowed - - -Structure: ----------- - -the headers MUST be in exactly the following order (to simplify demuxer design) -main header -stream_header (id=0) -stream_header (id=1) -... -stream_header (id=n) - -headers may be repeated, but if they are, then they MUST all be repeated -together and repeated headers MUST be identical - -Each set of repeated headers not at the beginning or end of the file SHOULD -be stored at the earliest possible position after 2^x where x is -an integer and the file end, so the headers may be repeated at 4102 if that is -the closest position after 2^12=4096 at which the headers can be placed - -Note: this allows an implementation reading the file to locate backup -headers in O(log filesize) time as opposed to O(filesize) - -headers MUST be placed at least at the start of the file and immediately before -the index or at the file end if there is no index -headers MUST be repeated at least twice (so they exist three times in a file) - -there MUST be a sync point immediately before the first frame after any headers - - -Index: ------- - -Note: with realtime streaming, there is no end, so no index there either -Index MAY only be repeated after main headers. -If an index is written anywhere in the file, it MUST be written at end of -file as well. - - -Info: ------ - -If a info packet is stored anywhere then a muxer MUST also store an identical -info packet after every main-stream-header set - -If a demuxer has seen several info packets with the same chapter_id and -stream_id then it MUST ignore all but the one with the highest position in -the file - -demxuxers SHOULD not search the whole file for info packets - -demuxer (non-normative): ------------------------- - -in the absence of a valid header at the beginning, players SHOULD search for -backup headers starting at offset 2^x; for each x players SHOULD end their -search at a particular offset when any startcode is found (including syncpoint) - - - -Semantic requirements: -====================== - -If more than one stream of a given stream class is present, each one SHOULD -have info tags specifying disposition, and if applicable, language. -It often highly improves usability and is therefore strongly encouraged. - -A demuxer MUST NOT demux a stream which contains more than one stream, or which -is wrapped in a structure to facilitate more than one stream or otherwise -duplicate the role of a container. any such file is to be considered invalid. -for example vorbis in ogg in nut is invalid, as is -mpegvideo+mpegaudio in mpeg-ps/ts in nut or dvvideo + dvaudio in dv in nut - - - -Sample code (Public Domain, & untested): -======================================== - -typedef BufferContext{ - uint8_t *buf; - uint8_t *buf_ptr; -}BufferContext; - -static inline uint64_t get_bytes(BufferContext *bc, int count){ - uint64_t val=0; - - assert(count>0 && count<9); - - for(i=0; i<count; i++){ - val <<=8; - val += *(bc->buf_ptr++); - } - - return val; -} - -static inline void put_bytes(BufferContext *bc, int count, uint64_t val){ - uint64_t val=0; - - assert(count>0 && count<9); - - for(i=count-1; i>=0; i--){ - *(bc->buf_ptr++)= val >> (8*i); - } - - return val; -} - -static inline uint64_t get_v(BufferContext *bc){ - uint64_t val= 0; - - for(; space_left(bc) > 0; ){ - int tmp= *(bc->buf_ptr++); - if(tmp&0x80) - val= (val<<7) + tmp - 0x80; - else - return (val<<7) + tmp; - } - - return -1; -} - -static inline int put_v(BufferContext *bc, uint64_t val){ - int i; - - if(space_left(bc) < 9) return -1; - - val &= 0x7FFFFFFFFFFFFFFFULL; // FIXME can only encode upto 63 bits currently - for(i=7; ; i+=7){ - if(val>>i == 0) break; - } - - for(i-=7; i>0; i-=7){ - *(bc->buf_ptr++)= 0x80 | (val>>i); - } - *(bc->buf_ptr++)= val&0x7F; - - return 0; -} - -static int64_t get_dts(int64_t pts, int64_t *pts_cache, int delay, int reset){ - if(reset) memset(pts_cache, -1, delay*sizeof(int64_t)); - - while(delay--){ - int64_t t= pts_cache[delay]; - if(t < pts){ - pts_cache[delay]= pts; - pts= t; - } - } - - return pts; -} - - - -Authors: -======== - -Folks from the MPlayer developers mailing list (http://www.mplayerhq.hu/). -Authors in alphabetical order: (FIXME! Tell us if we left you out) - Beregszaszi, Alex (alex@fsn.hu) - Bunkus, Moritz (moritz@bunkus.org) - Diedrich, Tobias (ranma+mplayer@tdiedrich.de) - Felker, Rich (dalias@aerifal.cx) - Franz, Fabian (FabianFranz@gmx.de) - Gereoffy, Arpad (arpi@thot.banki.hu) - Hess, Andreas (jaska@gmx.net) - Niedermayer, Michael (michaelni@gmx.at) - Shimon, Oded (ods15@ods15.dyndns.org)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DOCS/tech/nut.txt Thu Jul 13 10:29:21 2006 +0000 @@ -0,0 +1,927 @@ +================================== +NUT Open Container Format 20060713 +================================== + + + +Intro: +====== + +Features / goals: + (supported by the format, not necessarily by a specific implementation) + +Simple + use the same encoding for nearly all fields + simple decoding, so slow CPUs (and embedded systems) can handle it + +Extendible + no limit for the possible values of all fields (using universal vlc) + allow adding of new headers in the future + allow adding more fields at the end of headers + +Compact + ~0.2% overhead, for normal bitrates + index is <100kb per hour + a usual header for a file is about 100 bytes (audio + video headers together) + a packet header is about ~1-5 bytes + +Error resistant + seeking / playback without an index + headers & index can be repeated + damaged files can be played back with minimal data loss and fast + resync times + +The spec is frozen. All files following spec will be compatible unless the +spec is unfrozen. + + +Definitions: +============ + +MUST the specific part must be done to conform to this standard +SHOULD it is recommended to be done that way, but not strictly required + + + +Syntax: +======= + +Since NUT heavily uses variable length fields, the simplest way to describe it +is using a pseudocode approach. + + + +Conventions: +============ + +The data types have a name, used in the bitstream syntax description, a short +text description and a pseudocode (functional) definition, optional notes may +follow: + +name (text description) + functional definition + [Optional notes] + +The bitstream syntax elements have a tagname and a functional definition, they +are presented in a bottom up approach, again optional notes may follow and +are reproduced in the tag description: + +name: (optional note) + functional definition + [Optional notes] + +The in-depth tag description follows the bitstream syntax. +The functional definition has a C-like syntax. + + + +Type definitions: +================= + +f(n) (n fixed bits in big-endian order) +u(n) (unsigned number encoded in n bits in MSB-first order) + +v (variable length value, unsigned) + value=0 + do{ + more_data u(1) + data u(7) + value= 128*value + data + }while(more_data) + +s (variable length value, signed) + temp v + temp++ + if(temp&1) value= -(temp>>1) + else value= (temp>>1) + +b (binary data or string, to be use in vb, see below) + for(i=0; i<length; i++){ + data[i] u(8) + } + [Note: strings MUST be encoded in UTF-8] + [Note: the character NUL (U+0000) is not legal within + or at the end of a string.] + +vb (variable length binary data or string) + length v + value b + +t (v coded universal timestamp) + tmp v + id= tmp % time_base_count + value= (tmp / time_base_count) * time_base[id] + + +Bitstream syntax: +================= + +Common elements: +---------------- + +reserved_bytes: + for(i=0; i<forward_ptr - length_of_non_reserved; i++) + reserved u(8) + [a demuxer MUST ignore any reserved bytes + a muxer MUST NOT write any reserved bytes, as this would make it + impossible to add new fields at the end of packets in the future + in a compatible way] + +packet_header + startcode f(64) + forward_ptr v + if(forward_ptr > 4096) + header_checksum u(32) + +packet_footer + reserved_bytes + checksum u(32) + [Note: in index packet, reserved_bytes comes before index_ptr] + +reserved_headers + while(next_byte == 'N' && next_code != main_startcode + && next_code != stream_startcode + && next_code != info_startcode + && next_code != index_startcode + && next_code != syncpoint_startcode){ + packet_header + packet_footer + } + + Headers: + +main header: + version v + stream_count v + max_distance v + time_base_count v + for(i=0; i<time_base_count; i++) + time_base_nom v + time_base_denom v + time_base[i]= time_base_nom/time_base_denom + tmp_pts=0 + tmp_mul=1 + tmp_stream=0 + for(i=0; i<256; ){ + tmp_flag v + tmp_fields v + if(tmp_fields>0) tmp_pts s + if(tmp_fields>1) tmp_mul v + if(tmp_fields>2) tmp_stream v + if(tmp_fields>3) tmp_size v + else tmp_size=0 + if(tmp_fields>4) tmp_res v + else tmp_res=0 + if(tmp_fields>5) count v + else count= tmp_mul - tmp_size + for(j=6; j<tmp_fields; j++){ + tmp_reserved[i] v + } + for(j=0; j<count && i<256; j++, i++){ + if (i == 'N') { + flags[i]= FLAG_INVALID; + j--; + continue; + } + flags[i]= tmp_flag; + stream_id[i]= tmp_stream; + data_size_mul[i]= tmp_mul; + data_size_lsb[i]= tmp_size + j; + pts_delta[i]= tmp_pts; + reserved_count[i]= tmp_res; + } + } + +stream_header: + stream_id v + stream_class v + fourcc vb + time_base_id v + msb_pts_shift v + max_pts_distance v + decode_delay v + stream_flags v + codec_specific_data vb + if(stream_class == video){ + width v + height v + sample_width v + sample_height v + colorspace_type v + }else if(stream_class == audio){ + samplerate_nom v + samplerate_denom v + channel_count v + } + + Basic Packets: + +frame: + frame_code f(8) + frame_flags= flags[frame_code] + if(frame_flags&FLAG_CODED){ + coded_flags v + frame_flags ^= coded_flags + } + if(frame_flags&FLAG_STREAM_ID){ + stream_id v + } + if(frame_flags&FLAG_CODED_PTS){ + coded_pts v + } + if(frame_flags&FLAG_SIZE_MSB){ + data_size_msb v + } + if(frame_flags&FLAG_RESERVED) + reserved_count[frame_code] v + for(i=0; i<reserved_count[frame_code]; i++) + reserved v + if(frame_flags&FLAG_CHECKSUM){ + checksum u(32) + } + data + +index: + max_pts t + syncpoints v + for(i=0; i<syncpoints; i++){ + syncpoint_pos_div16 v + } + for(i=0; i<stream_count; i++){ + last_pts= -1 + for(j=0; j<syncpoints; ){ + x v + type= x & 1 + x>>=1 + n=j + if(type){ + flag= x & 1 + x>>=1 + while(x--) + has_keyframe[n++][i]=flag + has_keyframe[n++][i]=!flag; + }else{ + while(x != 1){ + has_keyframe[n++][i]=x&1; + x>>=1; + } + } + for(; j<n && j<syncpoints; j++){ + if (!has_keyframe[j][i]) continue + A v + if(!A){ + A v + B v + eor_pts[j][i] = last_pts + A + B + }else + B=0 + keyframe_pts[j][i] = last_pts + A + last_pts += A + B + } + } + } + reserved_bytes + index_ptr u(64) + +info_packet: + stream_id_plus1 v + chapter_id v + chapter_start t + chapter_len v + count v + for(i=0; i<count; i++){ + name vb + value s + if (value==-1){ + type= "UTF-8" + value vb + }else if (value==-2){ + type vb + value vb + }else if (value==-3){ + type= "s" + value s + }else if (value==-4){ + type= "t" + value t + }else if (value<-4){ + type= "r" + value.den= -value-4 + value.num s + }else{ + type= "v" + } + } + +syncpoint: + global_key_pts t + back_ptr_div16 v + + Complete definition: + +file: + file_id_string + while(!eof){ + if(next_byte == 'N'){ + packet_header + switch(startcode){ + case main_startcode: main_header; break; + case stream_startcode:stream_header; break; + case info_startcode: info_packet; break; + case index_startcode: index; break; + case syncpoint_startcode: syncpoint; break; + } + packet_footer + }else + frame + } + +the structure of a undamaged file should look like the following, but +demuxers should be flexible and be able to deal with damaged headers so the +above is a better loop in practice (not to mention its simpler) +note, demuxers MUST be able to deal with new and unknown headers + +file: + file_id_string + while(!eof){ + packet_header, main_header, packet_footer + reserved_headers + for(i=0; i<stream_count; i++){ + packet_header, stream_header, packet_footer + reserved_headers + } + while(next_code == info_startcode){ + packet_header, info_packet, packet_footer + reserved_headers + } + if(next_code == index_startcode){ + packet_header, index_packet, packet_footer + } + if (!eof) while(next_code != main_startcode){ + if(next_code == syncpoint_startcode){ + packet_header, syncpoint, packet_footer + } + frame + reserved_headers + } + } + + +Tag description: +---------------- + +file_id_string + "nut/multimedia container\0" + +*_startcode + all startcodes start with 'N' + +main_startcode + 0x7A561F5F04ADULL + (((uint64_t)('N'<<8) + 'M')<<48) + +stream_starcode + 0x11405BF2F9DBULL + (((uint64_t)('N'<<8) + 'S')<<48) + +syncpoint_startcode + 0xE4ADEECA4569ULL + (((uint64_t)('N'<<8) + 'K')<<48) + +index_startcode + 0xDD672F23E64EULL + (((uint64_t)('N'<<8) + 'X')<<48) + +info_startcode + 0xAB68B596BA78ULL + (((uint64_t)('N'<<8) + 'I')<<48) + +version + NUT version. The current value is 3. All lower values are pre-freeze + +forward_ptr + size of the packet data (exactly the distance from the first byte + after the packet_header to the first byte of the next packet) + +max_distance + max distance between startcodes. If p1 and p2 are the byte + positions of the first byte of two consecutive startcodes, then + p2-p1 MUST be less than or equal to max_distance unless the entire + span from p1 to p2 comprises a single packet or a syncpoint + followed by a single frame. This imposition places efficient upper + bounds on seek operations and allows for the detection of damaged + frame headers, should a chain of frame headers pass max_distance + without encountering any startcode. + + syncpoints SHOULD be placed immediately before a keyframe if the + previous frame of the same stream was a non-keyframe, unless such + non-keyframe - keyframe transitions are very frequent + + SHOULD be set to <=32768 + if the stored value is >65536 then max_distance MUST be set to 65536 + + This is also half the max frame size without a checksum after the + frameheader. + + +max_pts_distance + max absoloute difference of pts of new frame from last_pts in the + timebase of the stream, without a checksum after the frameheader. + A frame header MUST include a checksum if abs(pts-last_pts) is + strictly greater than max_pts_distance. + Note that last_pts is not necessarily the pts of the last frame + on the same stream, as it is altered by syncpoint timestamps. + SHOULD NOT be higher than 1/timebase + +stream_id + Stream identifier + stream_id MUST be < stream_count + +stream_class + 0 video + 1 audio + 2 subtiles + 3 userdata + Note: the remaining values are reserved and MUST NOT be used + a demuxer MUST ignore streams with reserved classes + +fourcc + identification for the codec + example: "H264" + MUST contain 2 or 4 bytes, note, this might be increased in the future + if needed + the id values used are the same as in avi, so if a codec uses a specific + fourcc in avi then the same fourcc MUST be used here + +time_base_nom / time_base_denom = time_base + the length of a timer tick in seconds, this MUST be equal to the 1/fps + if FLAG_FIXED_FPS is set + time_base_nom and time_base_denom MUST NOT be 0 + time_base_nom and time_base_denom MUST be relatively prime + time_base_denom MUST be < 2^31 + examples: + fps time_base_nom time_base_denom + 30 1 30 + 29.97 1001 30000 + 23.976 1001 24000 + There MUST NOT be 2 identical timebases in a file. + There SHOULD NOT be more timebases than streams. + +time_base_id + id to time_base table + +convert_ts + To switch from 2 different timebases, the following calculation is + defined: + + ln = from_time_base_nom*to_time_base_denom + sn = from_timestamp + d1 = from_time_base_denom + d2 = to_time_base_nom + timestamp = (ln/d1*sn + ln%d1*sn/d1)/d2 + Note: this calculation MUST be done with unsigned 64 bit integers, and + is equivalent to (ln*sn)/(d1*d2) but this would require a 96bit integer + +compare_ts + Compares timestamps from 2 different timebases, + if a is before b then compare_ts(a, b) = -1 + if a is after b then compare_ts(a, b) = 1 + else compare_ts(a, b) = 0 + + Care must be taken that this is done exactly with no rounding errors, + simply casting to float or double and doing the obvious + a*timebase > b*timebase is not compliant or correct, neither is the + same with integers, and + a*a_timebase.num*b_timebase.den > b*b_timebase.num*a_timebase.den + will overflow. One possible implementation which shouldn't overflow + within the range of legal timestamps and timebases is: + + if (convert_ts(a, a_timebase, b_timebase) < b) return -1; + if (convert_ts(b, b_timebase, a_timebase) < a) return 1; + return 0; + +msb_pts_shift + amount of bits in lsb_pts + MUST be <16 + +decode_delay + maximum time between input and output for a codec, used to generate + dts from pts + is set to 0 for streams without B-frames, and set to 1 for streams with + B-frames, may be larger for future codecs + decode_delay MUST NOT be set higher than necessary for a codec. + +stream_flags + Bit Name Description + 1 FLAG_FIXED_FPS indicates that the fps is fixed + +codec_specific_data + private global data for a codec (could be huffman tables or ...) + +frame_code + the meaning of this byte is stored in the main header + the value 78 ('N') is forbidden to ensure that the byte is always + different from the first byte of any startcode + a muxer SHOULD mark 0x00 and 0xFF as invalid to improve error + detection + +flags[frame_code], frame_flags + Bit Name Description + 1 FLAG_KEY if set, frame is keyframe + 2 FLAG_EOR if set, stream has no relevance on + presentation. (EOR) + 8 FLAG_CODED_PTS if set, coded_pts is in the frame header + 16 FLAG_STREAM_ID if set, stream_id is coded in the frame header + 32 FLAG_SIZE_MSB if set, data_size_msb is at frame header, + otherwise data_size_msb is 0 + 64 FLAG_CHECKSUM if set then the frame header contains a checksum + 128 FLAG_RESERVED if set, reserved_count is coded in the frame header + 4096 FLAG_CODED if set, coded_flags are stored in the frame header. + 8192 FLAG_INVALID if set, frame_code is invalid. + + EOR frames MUST be zero-length and must be set keyframe. + All streams SHOULD end with EOR, where the pts of the EOR indicates the + end presentation time of the final frame. + An EOR set stream is unset by the first content frames. + EOR can only be unset in streams with zero decode_delay . + FLAG_CHECKSUM MUST be set if the frame's data_size is strictly greater than + 2*max_distance or the difference abs(pts-last_pts) is strictly greater than + max_pts_distance (where pts represents this frame's pts and last_pts is + defined as below). + +stream_id[frame_code] + MUST be <250 + +data_size_mul[frame_code] + MUST be <16384 + +data_size_lsb[frame_code] + MUST be <16384 + +pts_delta[frame_code] + MUST be <16384 and >-16384 + +reserved_count[frame_code] + MUST be <256 + +data_size + data_size= data_size_lsb + data_size_msb*data_size_mul; + +coded_pts + if coded_pts < (1<<msb_pts_shift) then it is an lsb + pts, otherwise it is a full pts + (1<<msb_pts_shift) + lsb pts is converted to a full pts by: + mask = (1<<msb_pts_shift)-1; + delta = last_pts - mask/2 + pts = ((pts_lsb-delta)&mask) + delta + +lsb_pts + least significant bits of the pts in time_base precision + Example: IBBP display order + keyframe pts=0 -> pts=0 + frame lsb_pts=3 -> pts=3 + frame lsb_pts=1 -> pts=1 + frame lsb_pts=2 -> pts=2 + ... + keyframe msb_pts=257 -> pts=257 + frame lsb_pts=255 -> pts=255 + frame lsb_pts=0 -> pts=256 + frame lsb_pts=4 -> pts=260 + frame lsb_pts=2 -> pts=258 + frame lsb_pts=3 -> pts=259 + all pts's of keyframes of a single stream MUST be monotone + +dts + dts is calculated by using a decode_delay+1 sized buffer for each + stream, into which the current pts is inserted and the element with + the smallest value is removed, this is then the current dts + this buffer is initalized with decode_delay -1 elements + + Pts of all frames in all streams MUST be bigger or equal to dts of all + previous frames in all streams, compared in common timebase. (EOR + frames are NOT exempt from this rule) + +width/height + MUST be set to the coded width/height, MUST NOT be 0 + +sample_width/sample_height (aspect ratio) + sample_width is the horizontal distance between samples + sample_width and sample_height MUST be relatively prime if not zero + both MUST be 0 if unknown otherwise both MUST be non zero + +colorspace_type + 0 unknown + 1 ITU Rec 624 / ITU Rec 601 Y range: 16..235 Cb/Cr range: 16..240 + 2 ITU Rec 709 Y range: 16..235 Cb/Cr range: 16..240 + 17 ITU Rec 624 / ITU Rec 601 Y range: 0..255 Cb/Cr range: 0..255 + 18 ITU Rec 709 Y range: 0..255 Cb/Cr range: 0..255 + +samplerate_nom / samplerate_denom = samplerate + the number of samples per second, MUST NOT be 0 + +crc32 checksum + Generator polynomial is 0x104C11DB7. Starting value is zero. + +checksum + crc32 checksum + checksum is calculated for the area pointed to by forward_ptr not + including the checksum itself (from first byte after the + packet_header until last byte before the checksum). + for frame headers the checksum contains the framecode byte and all + following bytes upto the checksum itself + +header_checksum + checksum over the startcode and forward pointer + +Syncpoint tags: +--------------- + +back_ptr_div16 + back_ptr = back_ptr_div16 * 16 + 15 + back_ptr must point to a position within 16 bytes of a syncpoint + startcode. This syncpoint MUST be the closest syncpoint such that at + least one keyframe with a pts lower or equal to the original syncpoint's + global_key_pts for all streams lies between it and the current syncpoint. + + A stream where EOR is set is to be ignored for back_ptr. + +global_key_pts + After a syncpoint, last_pts of each stream is to be set to: + last_pts[i] = convert_ts(global_key_pts, time_base[id], time_base[i]) + + global_key_pts MUST be bigger or equal to dts of all past frames across + all streams, and smaller or equal to pts of all future frames. + +Index tags: +----------- + +max_pts + The highest pts in the entire file + +syncpoint_pos_div16 + offset from begginning of file to up to 15 bytes before the syncpoint + referred to in this index entry. Relative to position of last + syncpoint. + +has_keyframe + indicates whether this stream has a keyframe between this syncpoint and + the last syncpoint. + +keyframe_pts + The pts of the first keyframe for this stream in the region between the + 2 syncpoints, in the stream's timebase. (EOR frames are also keyframes) + +eor_pts + Coded only if EOR is set at the position of the syncpoint. The pts of + that EOR. EOR is unset by the first keyframe after it. + +index_ptr + Length in bytes of the entire index, from the first byte of the + startcode until the last byte of the checksum. + Note: A demuxer can use this to find the index when it is written at + EOF, as index_ptr will always be 12 bytes before the end of file if + there is an index at all. + + +Info tags: +---------- + +stream_id_plus1 + Stream this info packet applies to. If zero, packet applies to whole + file. + +chapter_id + Id of chapter this packet applies to. If zero, packet applies to whole + file. Positive chapter_id's are real chapters and MUST NOT overlap. + Negative chapter_id indicate a sub region of file and not a real + chapter. chapter_id MUST be unique to the region it represents. + chapter_id n MUST not be used unless there are at least n chapters in the + file + +chapter_start + timestamp of start of chapter + +chapter_len + Length of chapter in same timebase of chapter_start. + +type + for example: "UTF8" -> string or "JPEG" -> JPEG image + "v" -> unsigned integer + "s" -> signed integer + "r" -> rational + Note: nonstandard fields should be prefixed by "X-" + Note: MUST be less than 6 byte long (might be increased to 64 later) + +info packet types + the name of the info entry, valid names are + "Author" + "Description" + "Copyright" + "Encoder" + the name & version of the software used for encoding + "Title" + "Cover" (allowed types are "PNG" and "JPEG") + image of the (CD, DVD, VHS, ..) cover (preferably PNG or JPEG) + "Source" + "DVD", "VCD", "CD", "MD", "FM radio", "VHS", "TV", "LD" + Optional: appended PAL, NTSC, SECAM, ... in parentheses + "SourceContainer" + "nut", "mkv", "mov", "avi", "ogg", "rm", "mpeg-ps", "mpeg-ts", "raw" + "SourceCodecTag" + the source codec id like a fourcc which was used to store a specific + stream in its SourceContainer + "CaptureDevice" + "BT878", "BT848", "webcam", ... (more exact names are fine too) + "CreationTime" + "2003-01-20 20:13:15Z", ... + (ISO 8601 format, see http://www.cl.cam.ac.uk/~mgk25/iso-time.html) + Note: do not forget the timezone + "Keywords" + "Language" + ISO 639 and ISO 3166 for language/country code + something like "eng" (US english), can be 0 if unknown + and "multi" if several languages + see http://www.loc.gov/standards/iso639-2/englangn.html + and http://www.din.de/gremien/nas/nabd/iso3166ma/codlstp1/en_listp1.html + the language code + "Disposition" + "original", "dub" (translated), "comment", "lyrics", "karaoke" + Note: if someone needs some others, please tell us about them, so we + can add them to the official standard (if they are sane) + Note: nonstandard fields should be prefixed by "X-" + Note: names of fields SHOULD be in English if a word with the same + meaning exists in English + Note: MUST be less than 64 bytes long + +value + value of this name/type pair + +stuffing + 0x80 can be placed in front of any type v entry for stuffing purposes + except the forward_ptr and all fields in the frame header where a + maximum of 8 stuffing bytes per field are allowed + + +Structure: +---------- + +the headers MUST be in exactly the following order (to simplify demuxer design) +main header +stream_header (id=0) +stream_header (id=1) +... +stream_header (id=n) + +headers may be repeated, but if they are, then they MUST all be repeated +together and repeated headers MUST be identical + +Each set of repeated headers not at the beginning or end of the file SHOULD +be stored at the earliest possible position after 2^x where x is +an integer and the file end, so the headers may be repeated at 4102 if that is +the closest position after 2^12=4096 at which the headers can be placed + +Note: this allows an implementation reading the file to locate backup +headers in O(log filesize) time as opposed to O(filesize) + +headers MUST be placed at least at the start of the file and immediately before +the index or at the file end if there is no index +headers MUST be repeated at least twice (so they exist three times in a file) + +there MUST be a sync point immediately before the first frame after any headers + + +Index: +------ + +Note: with realtime streaming, there is no end, so no index there either +Index MAY only be repeated after main headers. +If an index is written anywhere in the file, it MUST be written at end of +file as well. + + +Info: +----- + +If a info packet is stored anywhere then a muxer MUST also store an identical +info packet after every main-stream-header set + +If a demuxer has seen several info packets with the same chapter_id and +stream_id then it MUST ignore all but the one with the highest position in +the file + +demxuxers SHOULD not search the whole file for info packets + +demuxer (non-normative): +------------------------ + +in the absence of a valid header at the beginning, players SHOULD search for +backup headers starting at offset 2^x; for each x players SHOULD end their +search at a particular offset when any startcode is found (including syncpoint) + + + +Semantic requirements: +====================== + +If more than one stream of a given stream class is present, each one SHOULD +have info tags specifying disposition, and if applicable, language. +It often highly improves usability and is therefore strongly encouraged. + +A demuxer MUST NOT demux a stream which contains more than one stream, or which +is wrapped in a structure to facilitate more than one stream or otherwise +duplicate the role of a container. any such file is to be considered invalid. +for example vorbis in ogg in nut is invalid, as is +mpegvideo+mpegaudio in mpeg-ps/ts in nut or dvvideo + dvaudio in dv in nut + + + +Sample code (Public Domain, & untested): +======================================== + +typedef BufferContext{ + uint8_t *buf; + uint8_t *buf_ptr; +}BufferContext; + +static inline uint64_t get_bytes(BufferContext *bc, int count){ + uint64_t val=0; + + assert(count>0 && count<9); + + for(i=0; i<count; i++){ + val <<=8; + val += *(bc->buf_ptr++); + } + + return val; +} + +static inline void put_bytes(BufferContext *bc, int count, uint64_t val){ + uint64_t val=0; + + assert(count>0 && count<9); + + for(i=count-1; i>=0; i--){ + *(bc->buf_ptr++)= val >> (8*i); + } + + return val; +} + +static inline uint64_t get_v(BufferContext *bc){ + uint64_t val= 0; + + for(; space_left(bc) > 0; ){ + int tmp= *(bc->buf_ptr++); + if(tmp&0x80) + val= (val<<7) + tmp - 0x80; + else + return (val<<7) + tmp; + } + + return -1; +} + +static inline int put_v(BufferContext *bc, uint64_t val){ + int i; + + if(space_left(bc) < 9) return -1; + + val &= 0x7FFFFFFFFFFFFFFFULL; // FIXME can only encode upto 63 bits currently + for(i=7; ; i+=7){ + if(val>>i == 0) break; + } + + for(i-=7; i>0; i-=7){ + *(bc->buf_ptr++)= 0x80 | (val>>i); + } + *(bc->buf_ptr++)= val&0x7F; + + return 0; +} + +static int64_t get_dts(int64_t pts, int64_t *pts_cache, int delay, int reset){ + if(reset) memset(pts_cache, -1, delay*sizeof(int64_t)); + + while(delay--){ + int64_t t= pts_cache[delay]; + if(t < pts){ + pts_cache[delay]= pts; + pts= t; + } + } + + return pts; +} + + + +Authors: +======== + +Folks from the MPlayer developers mailing list (http://www.mplayerhq.hu/). +Authors in alphabetical order: (FIXME! Tell us if we left you out) + Beregszaszi, Alex (alex@fsn.hu) + Bunkus, Moritz (moritz@bunkus.org) + Diedrich, Tobias (ranma+mplayer@tdiedrich.de) + Felker, Rich (dalias@aerifal.cx) + Franz, Fabian (FabianFranz@gmx.de) + Gereoffy, Arpad (arpi@thot.banki.hu) + Hess, Andreas (jaska@gmx.net) + Niedermayer, Michael (michaelni@gmx.at) + Shimon, Oded (ods15@ods15.dyndns.org)