diff options
author | Jeremy Andrews <athenian200@outlook.com> | 2021-09-25 17:11:41 -0500 |
---|---|---|
committer | Jeremy Andrews <athenian200@outlook.com> | 2021-09-25 17:11:41 -0500 |
commit | bb475eb5a46dc1de728a14980b1bb393144f7b7d (patch) | |
tree | 29f65443c253ed175af77f4e3df164ce8bbd03a3 /media | |
parent | 68b5502ed36f3dc773e6bda83eeccfc25e014718 (diff) | |
download | aura-central-bb475eb5a46dc1de728a14980b1bb393144f7b7d.tar.gz |
Issue %3003 - Move libnestegg to libs/
Diffstat (limited to 'media')
-rw-r--r-- | media/libnestegg/AUTHORS | 3 | ||||
-rw-r--r-- | media/libnestegg/LICENSE | 13 | ||||
-rw-r--r-- | media/libnestegg/README.md | 5 | ||||
-rw-r--r-- | media/libnestegg/README_MCP | 8 | ||||
-rw-r--r-- | media/libnestegg/include/moz.build | 9 | ||||
-rw-r--r-- | media/libnestegg/include/nestegg.h | 486 | ||||
-rw-r--r-- | media/libnestegg/moz.build | 7 | ||||
-rw-r--r-- | media/libnestegg/src/moz.build | 16 | ||||
-rw-r--r-- | media/libnestegg/src/nestegg.c | 3200 | ||||
-rwxr-xr-x | media/libnestegg/update.sh | 22 |
10 files changed, 0 insertions, 3769 deletions
diff --git a/media/libnestegg/AUTHORS b/media/libnestegg/AUTHORS deleted file mode 100644 index 7d2c61265..000000000 --- a/media/libnestegg/AUTHORS +++ /dev/null @@ -1,3 +0,0 @@ -Matthew Gregan <kinetik@flim.org> -Steve Workman <sjhworkman@gmail.com> -Paul Adenot <paul@paul.cx> diff --git a/media/libnestegg/LICENSE b/media/libnestegg/LICENSE deleted file mode 100644 index a67984a61..000000000 --- a/media/libnestegg/LICENSE +++ /dev/null @@ -1,13 +0,0 @@ -Copyright © 2010 Mozilla Foundation - -Permission to use, copy, modify, and distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/media/libnestegg/README.md b/media/libnestegg/README.md deleted file mode 100644 index ce9bd76ff..000000000 --- a/media/libnestegg/README.md +++ /dev/null @@ -1,5 +0,0 @@ -[![Build Status](https://travis-ci.org/kinetiknz/nestegg.svg?branch=master)](https://travis-ci.org/kinetiknz/nestegg) - -See INSTALL for build instructions. - -Licensed under an ISC-style license. See LICENSE for details. diff --git a/media/libnestegg/README_MCP b/media/libnestegg/README_MCP deleted file mode 100644 index e738fd920..000000000 --- a/media/libnestegg/README_MCP +++ /dev/null @@ -1,8 +0,0 @@ -The source from this directory was copied from the nestegg -git repository using the update.sh script. The only changes -made were those applied by update.sh and the addition of -Makefile.in build files for the Mozilla build system. - -The nestegg git repository is: https://github.com/kinetiknz/nestegg - -The git commit ID used was f7a0b7cedc893b6683cf15cb210b1656c086d964. diff --git a/media/libnestegg/include/moz.build b/media/libnestegg/include/moz.build deleted file mode 100644 index 8c4517e2a..000000000 --- a/media/libnestegg/include/moz.build +++ /dev/null @@ -1,9 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -EXPORTS.nestegg += [ - 'nestegg.h', -] - diff --git a/media/libnestegg/include/nestegg.h b/media/libnestegg/include/nestegg.h deleted file mode 100644 index 2a9f08f5d..000000000 --- a/media/libnestegg/include/nestegg.h +++ /dev/null @@ -1,486 +0,0 @@ -/* - * Copyright © 2010 Mozilla Foundation - * - * This program is made available under an ISC-style license. See the - * accompanying file LICENSE for details. - */ -#if !defined(NESTEGG_671cac2a_365d_ed69_d7a3_4491d3538d79) -#define NESTEGG_671cac2a_365d_ed69_d7a3_4491d3538d79 - -#include <limits.h> -#include <stdint.h> - -#if defined(__cplusplus) -extern "C" { -#endif - -/** @mainpage - - @section intro Introduction - - This is the documentation for the <tt>libnestegg</tt> C API. - <tt>libnestegg</tt> is a demultiplexing library for <a - href="http://www.webmproject.org/code/specs/container/">WebM</a> - media files. - - @section example Example code - - @code - nestegg * demux_ctx; - nestegg_init(&demux_ctx, io, NULL, -1); - - nestegg_packet * pkt; - while ((r = nestegg_read_packet(demux_ctx, &pkt)) > 0) { - unsigned int track; - - nestegg_packet_track(pkt, &track); - - // This example decodes the first track only. - if (track == 0) { - unsigned int chunk, chunks; - - nestegg_packet_count(pkt, &chunks); - - // Decode each chunk of data. - for (chunk = 0; chunk < chunks; ++chunk) { - unsigned char * data; - size_t data_size; - - nestegg_packet_data(pkt, chunk, &data, &data_size); - - example_codec_decode(codec_ctx, data, data_size); - } - } - - nestegg_free_packet(pkt); - } - - nestegg_destroy(demux_ctx); - @endcode -*/ - - -/** @file - The <tt>libnestegg</tt> C API. */ - -#define NESTEGG_TRACK_VIDEO 0 /**< Track is of type video. */ -#define NESTEGG_TRACK_AUDIO 1 /**< Track is of type audio. */ -#define NESTEGG_TRACK_UNKNOWN INT_MAX /**< Track is of type unknown. */ - -#define NESTEGG_CODEC_VP8 0 /**< Track uses Google On2 VP8 codec. */ -#define NESTEGG_CODEC_VORBIS 1 /**< Track uses Xiph Vorbis codec. */ -#define NESTEGG_CODEC_VP9 2 /**< Track uses Google On2 VP9 codec. */ -#define NESTEGG_CODEC_OPUS 3 /**< Track uses Xiph Opus codec. */ -#define NESTEGG_CODEC_AV1 4 /**< Track uses AOMedia AV1 codec. */ -#define NESTEGG_CODEC_AVC1 5 /**< Track uses AVC1 'h264' */ -#define NESTEGG_CODEC_AAC 6 /**< Track uses AAC 'mp4a' */ -#define NESTEGG_CODEC_UNKNOWN INT_MAX /**< Track uses unknown codec. */ - -#define NESTEGG_VIDEO_MONO 0 /**< Track is mono video. */ -#define NESTEGG_VIDEO_STEREO_LEFT_RIGHT 1 /**< Track is side-by-side stereo video. Left first. */ -#define NESTEGG_VIDEO_STEREO_BOTTOM_TOP 2 /**< Track is top-bottom stereo video. Right first. */ -#define NESTEGG_VIDEO_STEREO_TOP_BOTTOM 3 /**< Track is top-bottom stereo video. Left first. */ -#define NESTEGG_VIDEO_STEREO_RIGHT_LEFT 11 /**< Track is side-by-side stereo video. Right first. */ - -#define NESTEGG_SEEK_SET 0 /**< Seek offset relative to beginning of stream. */ -#define NESTEGG_SEEK_CUR 1 /**< Seek offset relative to current position in stream. */ -#define NESTEGG_SEEK_END 2 /**< Seek offset relative to end of stream. */ - -#define NESTEGG_LOG_DEBUG 1 /**< Debug level log message. */ -#define NESTEGG_LOG_INFO 10 /**< Informational level log message. */ -#define NESTEGG_LOG_WARNING 100 /**< Warning level log message. */ -#define NESTEGG_LOG_ERROR 1000 /**< Error level log message. */ -#define NESTEGG_LOG_CRITICAL 10000 /**< Critical level log message. */ - -#define NESTEGG_ENCODING_COMPRESSION 0 /**< Content encoding type is compression. */ -#define NESTEGG_ENCODING_ENCRYPTION 1 /**< Content encoding type is encryption. */ - -#define NESTEGG_PACKET_HAS_SIGNAL_BYTE_FALSE 0 /**< Packet does not have signal byte */ -#define NESTEGG_PACKET_HAS_SIGNAL_BYTE_UNENCRYPTED 1 /**< Packet has signal byte and is unencrypted */ -#define NESTEGG_PACKET_HAS_SIGNAL_BYTE_ENCRYPTED 2 /**< Packet has signal byte and is encrypted */ -#define NESTEGG_PACKET_HAS_SIGNAL_BYTE_PARTITIONED 4 /**< Packet has signal byte and is partitioned */ - -#define NESTEGG_PACKET_HAS_KEYFRAME_FALSE 0 /**< Packet contains only keyframes. */ -#define NESTEGG_PACKET_HAS_KEYFRAME_TRUE 1 /**< Packet does not contain any keyframes */ -#define NESTEGG_PACKET_HAS_KEYFRAME_UNKNOWN 2 /**< Packet may or may not contain keyframes */ - -typedef struct nestegg nestegg; /**< Opaque handle referencing the stream state. */ -typedef struct nestegg_packet nestegg_packet; /**< Opaque handle referencing a packet of data. */ - -/** User supplied IO context. */ -typedef struct { - /** User supplied read callback. - @param buffer Buffer to read data into. - @param length Length of supplied buffer in bytes. - @param userdata The #userdata supplied by the user. - @retval 1 Read succeeded. - @retval 0 End of stream. - @retval -1 Error. */ - int (* read)(void * buffer, size_t length, void * userdata); - - /** User supplied seek callback. - @param offset Offset within the stream to seek to. - @param whence Seek direction. One of #NESTEGG_SEEK_SET, - #NESTEGG_SEEK_CUR, or #NESTEGG_SEEK_END. - @param userdata The #userdata supplied by the user. - @retval 0 Seek succeeded. - @retval -1 Error. */ - int (* seek)(int64_t offset, int whence, void * userdata); - - /** User supplied tell callback. - @param userdata The #userdata supplied by the user. - @returns Current position within the stream. - @retval -1 Error. */ - int64_t (* tell)(void * userdata); - - /** User supplied pointer to be passed to the IO callbacks. */ - void * userdata; -} nestegg_io; - -/** Parameters specific to a video track. */ -typedef struct { - unsigned int stereo_mode; /**< Video mode. One of #NESTEGG_VIDEO_MONO, - #NESTEGG_VIDEO_STEREO_LEFT_RIGHT, - #NESTEGG_VIDEO_STEREO_BOTTOM_TOP, or - #NESTEGG_VIDEO_STEREO_TOP_BOTTOM. */ - unsigned int width; /**< Width of the video frame in pixels. */ - unsigned int height; /**< Height of the video frame in pixels. */ - unsigned int display_width; /**< Display width of the video frame in pixels. */ - unsigned int display_height; /**< Display height of the video frame in pixels. */ - unsigned int crop_bottom; /**< Pixels to crop from the bottom of the frame. */ - unsigned int crop_top; /**< Pixels to crop from the top of the frame. */ - unsigned int crop_left; /**< Pixels to crop from the left of the frame. */ - unsigned int crop_right; /**< Pixels to crop from the right of the frame. */ - unsigned int alpha_mode; /**< 1 if an additional opacity stream is available, otherwise 0. */ -} nestegg_video_params; - -/** Parameters specific to an audio track. */ -typedef struct { - double rate; /**< Sampling rate in Hz. */ - unsigned int channels; /**< Number of audio channels. */ - unsigned int depth; /**< Bits per sample. */ - uint64_t codec_delay; /**< Nanoseconds that must be discarded from the start. */ - uint64_t seek_preroll;/**< Nanoseconds that must be discarded after a seek. */ -} nestegg_audio_params; - -/** Logging callback function pointer. */ -typedef void (* nestegg_log)(nestegg * context, unsigned int severity, char const * format, ...); - -/** Initialize a nestegg context. During initialization the parser will - read forward in the stream processing all elements until the first - block of media is reached. All track metadata has been processed at this point. - @param context Storage for the new nestegg context. @see nestegg_destroy - @param io User supplied IO context. - @param callback Optional logging callback function pointer. May be NULL. - @param max_offset Optional maximum offset to be read. Set -1 to ignore. - @retval 0 Success. - @retval -1 Error. */ -int nestegg_init(nestegg ** context, nestegg_io io, nestegg_log callback, int64_t max_offset); - -/** Destroy a nestegg context and free associated memory. - @param context #nestegg context to be freed. @see nestegg_init */ -void nestegg_destroy(nestegg * context); - -/** Query the duration of the media stream in nanoseconds. - @param context Stream context initialized by #nestegg_init. - @param duration Storage for the queried duration. - @retval 0 Success. - @retval -1 Error. */ -int nestegg_duration(nestegg * context, uint64_t * duration); - -/** Query the tstamp scale of the media stream in nanoseconds. - @note Timestamps presented by nestegg have been scaled by this value - before presentation to the caller. - @param context Stream context initialized by #nestegg_init. - @param scale Storage for the queried scale factor. - @retval 0 Success. - @retval -1 Error. */ -int nestegg_tstamp_scale(nestegg * context, uint64_t * scale); - -/** Query the number of tracks in the media stream. - @param context Stream context initialized by #nestegg_init. - @param tracks Storage for the queried track count. - @retval 0 Success. - @retval -1 Error. */ -int nestegg_track_count(nestegg * context, unsigned int * tracks); - -/** Query the start and end offset for a particular cluster. - @param context Stream context initialized by #nestegg_init. - @param cluster_num Zero-based cluster number; order they appear in cues. - @param max_offset Optional maximum offset to be read. Set -1 to ignore. - @param start_pos Starting offset of the cluster. -1 means non-existant. - @param end_pos Starting offset of the cluster. -1 means non-existant or - final cluster. - @param tstamp Starting timestamp of the cluster. - @retval 0 Success. - @retval -1 Error. */ -int nestegg_get_cue_point(nestegg * context, unsigned int cluster_num, - int64_t max_offset, int64_t * start_pos, - int64_t * end_pos, uint64_t * tstamp); - -/** Seek to @a offset. Stream will seek directly to offset. - Must be used to seek to the start of a cluster; the parser will not be - able to understand other offsets. - @param context Stream context initialized by #nestegg_init. - @param offset Absolute offset in bytes. - @retval 0 Success. - @retval -1 Error. */ -int nestegg_offset_seek(nestegg * context, uint64_t offset); - -/** Seek @a track to @a tstamp. Stream seek will terminate at the earliest - key point in the stream at or before @a tstamp. Other tracks in the - stream will output packets with unspecified but nearby timestamps. - @param context Stream context initialized by #nestegg_init. - @param track Zero based track number. - @param tstamp Absolute timestamp in nanoseconds. - @retval 0 Success. - @retval -1 Error. */ -int nestegg_track_seek(nestegg * context, unsigned int track, uint64_t tstamp); - -/** Query the type specified by @a track. - @param context Stream context initialized by #nestegg_init. - @param track Zero based track number. - @retval #NESTEGG_TRACK_VIDEO Track type is video. - @retval #NESTEGG_TRACK_AUDIO Track type is audio. - @retval #NESTEGG_TRACK_UNKNOWN Track type is unknown. - @retval -1 Error. */ -int nestegg_track_type(nestegg * context, unsigned int track); - -/** Query the codec ID specified by @a track. - @param context Stream context initialized by #nestegg_init. - @param track Zero based track number. - @retval #NESTEGG_CODEC_VP8 Track codec is VP8. - @retval #NESTEGG_CODEC_VP9 Track codec is VP9. - @retval #NESTEGG_CODEC_AV1 Track codec is AV1. - @retval #NESTEGG_CODEC_VORBIS Track codec is Vorbis. - @retval #NESTEGG_CODEC_OPUS Track codec is Opus. - @retval #NESTEGG_CODEC_UNKNOWN Track codec is unknown. - @retval -1 Error. */ -int nestegg_track_codec_id(nestegg * context, unsigned int track); - -/** Query the number of codec initialization chunks for @a track. Each - chunk of data should be passed to the codec initialization functions in - the order returned. - @param context Stream context initialized by #nestegg_init. - @param track Zero based track number. - @param count Storage for the queried chunk count. - @retval 0 Success. - @retval -1 Error. */ -int nestegg_track_codec_data_count(nestegg * context, unsigned int track, - unsigned int * count); - -/** Get a pointer to chunk number @a item of codec initialization data for - @a track. - @param context Stream context initialized by #nestegg_init. - @param track Zero based track number. - @param item Zero based chunk item number. - @param data Storage for the queried data pointer. - The data is owned by the #nestegg context. - @param length Storage for the queried data size. - @retval 0 Success. - @retval -1 Error. */ -int nestegg_track_codec_data(nestegg * context, unsigned int track, unsigned int item, - unsigned char ** data, size_t * length); - -/** Query the video parameters specified by @a track. - @param context Stream context initialized by #nestegg_init. - @param track Zero based track number. - @param params Storage for the queried video parameters. - @retval 0 Success. - @retval -1 Error. */ -int nestegg_track_video_params(nestegg * context, unsigned int track, - nestegg_video_params * params); - -/** Query the audio parameters specified by @a track. - @param context Stream context initialized by #nestegg_init. - @param track Zero based track number. - @param params Storage for the queried audio parameters. - @retval 0 Success. - @retval -1 Error. */ -int nestegg_track_audio_params(nestegg * context, unsigned int track, - nestegg_audio_params * params); - -/** Query the encoding status for @a track. If a track has multiple encodings - the first will be returned. - @param context Stream context initialized by #nestegg_init. - @param track Zero based track number. - @retval #NESTEGG_ENCODING_COMPRESSION The track is compressed, but not encrypted. - @retval #NESTEGG_ENCODING_ENCRYPTION The track is encrypted and compressed. - @retval -1 Error. */ -int nestegg_track_encoding(nestegg * context, unsigned int track); - -/** Query the ContentEncKeyId for @a track. Will return an error if the track - in not encrypted, or is not recognized. - @param context Stream context initialized by #nestegg_init. - @param track Zero based track number. - @param content_enc_key_id Storage for queried id. The content encryption key used. - Owned by nestegg and will be freed separately. - @param content_enc_key_id_length Length of the queried ContentEncKeyId in bytes. - @retval 0 Success. - @retval -1 Error. */ -int nestegg_track_content_enc_key_id(nestegg * context, unsigned int track, - unsigned char const ** content_enc_key_id, - size_t * content_enc_key_id_length); - -/** Query the default frame duration for @a track. For a video track, this - is typically the inverse of the video frame rate. - @param context Stream context initialized by #nestegg_init. - @param track Zero based track number. - @param duration Storage for the default duration in nanoseconds. - @retval 0 Success. - @retval -1 Error. */ -int nestegg_track_default_duration(nestegg * context, unsigned int track, - uint64_t * duration); - -/** Reset parser state to the last valid state before nestegg_read_packet failed. - @param context Stream context initialized by #nestegg_init. - @retval 0 Success. - @retval -1 Error. */ -int nestegg_read_reset(nestegg * context); - -/** Read a packet of media data. A packet consists of one or more chunks of - data associated with a single track. nestegg_read_packet should be - called in a loop while the return value is 1 to drive the stream parser - forward. @see nestegg_free_packet - @param context Context returned by #nestegg_init. - @param packet Storage for the returned nestegg_packet. - @retval 1 Additional packets may be read in subsequent calls. - @retval 0 End of stream. - @retval -1 Error. */ -int nestegg_read_packet(nestegg * context, nestegg_packet ** packet); - -/** Destroy a nestegg_packet and free associated memory. - @param packet #nestegg_packet to be freed. @see nestegg_read_packet */ -void nestegg_free_packet(nestegg_packet * packet); - -/** Query the keyframe status for a given packet. - @param packet Packet initialized by #nestegg_read_packet. - @retval #NESTEGG_PACKET_HAS_KEYFRAME_FALSE Packet contains no keyframes. - @retval #NESTEGG_PACKET_HAS_KEYFRAME_TRUE Packet contains keyframes. - @retval #NESTEGG_PACKET_HAS_KEYFRAME_UNKNOWN Unknown packet keyframe content. - @retval -1 Error. */ -int nestegg_packet_has_keyframe(nestegg_packet * packet); - -/** Query the track number of @a packet. - @param packet Packet initialized by #nestegg_read_packet. - @param track Storage for the queried zero based track index. - @retval 0 Success. - @retval -1 Error. */ -int nestegg_packet_track(nestegg_packet * packet, unsigned int * track); - -/** Query the timestamp in nanoseconds of @a packet. - @param packet Packet initialized by #nestegg_read_packet. - @param tstamp Storage for the queried timestamp in nanoseconds. - @retval 0 Success. - @retval -1 Error. */ -int nestegg_packet_tstamp(nestegg_packet * packet, uint64_t * tstamp); - -/** Query the duration in nanoseconds of @a packet. - @param packet Packet initialized by #nestegg_read_packet. - @param duration Storage for the queried duration in nanoseconds. - @retval 0 Success. - @retval -1 Error. */ -int nestegg_packet_duration(nestegg_packet * packet, uint64_t * duration); - -/** Query the number of data chunks contained in @a packet. - @param packet Packet initialized by #nestegg_read_packet. - @param count Storage for the queried chunk count. - @retval 0 Success. - @retval -1 Error. */ -int nestegg_packet_count(nestegg_packet * packet, unsigned int * count); - -/** Get a pointer to chunk number @a item of packet data. - @param packet Packet initialized by #nestegg_read_packet. - @param item Zero based chunk item number. - @param data Storage for the queried data pointer. - The data is owned by the #nestegg_packet packet. - @param length Storage for the queried data size. - @retval 0 Success. - @retval -1 Error. */ -int nestegg_packet_data(nestegg_packet * packet, unsigned int item, - unsigned char ** data, size_t * length); - -/** Get a pointer to additional data with identifier @a id of additional packet - data. If @a id isn't present in the packet, returns -1. - @param packet Packet initialized by #nestegg_read_packet. - @param id Codec specific identifer. For VP8, use 1 to get a VP8 encoded - frame containing an alpha channel in its Y plane. - @param data Storage for the queried data pointer. - The data is owned by the #nestegg_packet packet. - @param length Storage for the queried data size. - @retval 0 Success. - @retval -1 Error. */ -int nestegg_packet_additional_data(nestegg_packet * packet, unsigned int id, - unsigned char ** data, size_t * length); - -/** Returns discard_padding for given packet - @param packet Packet initialized by #nestegg_read_packet. - @param discard_padding pointer to store discard padding in. - @retval 0 Success. - @retval -1 Error. */ -int nestegg_packet_discard_padding(nestegg_packet * packet, - int64_t * discard_padding); - -/** Query if a packet is encrypted. - @param packet Packet initialized by #nestegg_read_packet. - @retval #NESTEGG_PACKET_HAS_SIGNAL_BYTE_FALSE No signal byte, encryption - information not read from packet. - @retval #NESTEGG_PACKET_HAS_SIGNAL_BYTE_UNENCRYPTED Encrypted bit not - set, encryption information not read from packet. - @retval #NESTEGG_PACKET_HAS_SIGNAL_BYTE_ENCRYPTED Encrypted bit set, - encryption infomation read from packet. - @retval #NESTEGG_PACKET_HAS_SIGNAL_BYTE_PARTITIONED Partitioned bit set, - encryption and parition information read from packet. - @retval -1 Error.*/ -int nestegg_packet_encryption(nestegg_packet * packet); - -/** Query the IV for an encrypted packet. Expects a packet from an encrypted - track, and will return error if given a packet that has no signal btye. - @param packet Packet initialized by #nestegg_read_packet. - @param iv Storage for queried iv. - @param length Length of returned iv, may be 0. - The data is owned by the #nestegg_packet packet. - @retval 0 Success. - @retval -1 Error. - */ -int nestegg_packet_iv(nestegg_packet * packet, unsigned char const ** iv, - size_t * length); - -/** Query the packet for offsets. -@param packet Packet initialized by #nestegg_read_packet. -@param partition_offsets Storage for queried offsets. -@param num_offsets Length of returned offsets, may be 0. -The data is owned by the #nestegg_packet packet. -@retval 0 Success. -@retval -1 Error. -*/ -int nestegg_packet_offsets(nestegg_packet * packet, - uint32_t const ** partition_offsets, - uint8_t * num_offsets); - -/** Returns reference_block given packet - @param packet Packet initialized by #nestegg_read_packet. - @param reference_block pointer to store reference block in. - @retval 0 Success. - @retval -1 Error. */ -int nestegg_packet_reference_block(nestegg_packet * packet, - int64_t * reference_block); - -/** Query the presence of cues. - @param context Stream context initialized by #nestegg_init. - @retval 0 The media has no cues. - @retval 1 The media has cues. */ -int nestegg_has_cues(nestegg * context); - -/** Try to determine if the buffer looks like the beginning of a WebM file. - @param buffer A buffer containing the beginning of a media file. - @param length The size of the buffer. - @retval 0 The file is not a WebM file. - @retval 1 The file is a WebM file. */ -int nestegg_sniff(unsigned char const * buffer, size_t length); - -#if defined(__cplusplus) -} -#endif - -#endif /* NESTEGG_671cac2a_365d_ed69_d7a3_4491d3538d79 */ diff --git a/media/libnestegg/moz.build b/media/libnestegg/moz.build deleted file mode 100644 index 16bb84e0f..000000000 --- a/media/libnestegg/moz.build +++ /dev/null @@ -1,7 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -DIRS += ['include', 'src'] - diff --git a/media/libnestegg/src/moz.build b/media/libnestegg/src/moz.build deleted file mode 100644 index bf9edcdbc..000000000 --- a/media/libnestegg/src/moz.build +++ /dev/null @@ -1,16 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -UNIFIED_SOURCES += [ - 'nestegg.c', -] - -if CONFIG['GKMEDIAS_SHARED_LIBRARY']: - NO_VISIBILITY_FLAGS = True - -FINAL_LIBRARY = 'gkmedias' - -# We allow warnings for third-party code that can be updated from upstream. -ALLOW_COMPILER_WARNINGS = True diff --git a/media/libnestegg/src/nestegg.c b/media/libnestegg/src/nestegg.c deleted file mode 100644 index 051bc50fa..000000000 --- a/media/libnestegg/src/nestegg.c +++ /dev/null @@ -1,3200 +0,0 @@ -/* - * Copyright © 2010 Mozilla Foundation - * - * This program is made available under an ISC-style license. See the - * accompanying file LICENSE for details. - */ -#include <assert.h> -#include <stddef.h> -#include <stdlib.h> -#include <string.h> - -#include "nestegg/nestegg.h" - -/* EBML Elements */ -#define ID_EBML 0x1a45dfa3 -#define ID_EBML_VERSION 0x4286 -#define ID_EBML_READ_VERSION 0x42f7 -#define ID_EBML_MAX_ID_LENGTH 0x42f2 -#define ID_EBML_MAX_SIZE_LENGTH 0x42f3 -#define ID_DOCTYPE 0x4282 -#define ID_DOCTYPE_VERSION 0x4287 -#define ID_DOCTYPE_READ_VERSION 0x4285 - -/* Global Elements */ -#define ID_VOID 0xec -#define ID_CRC32 0xbf - -/* WebM Elements */ -#define ID_SEGMENT 0x18538067 - -/* Seek Head Elements */ -#define ID_SEEK_HEAD 0x114d9b74 -#define ID_SEEK 0x4dbb -#define ID_SEEK_ID 0x53ab -#define ID_SEEK_POSITION 0x53ac - -/* Info Elements */ -#define ID_INFO 0x1549a966 -#define ID_TIMECODE_SCALE 0x2ad7b1 -#define ID_DURATION 0x4489 - -/* Cluster Elements */ -#define ID_CLUSTER 0x1f43b675 -#define ID_TIMECODE 0xe7 -#define ID_BLOCK_GROUP 0xa0 -#define ID_SIMPLE_BLOCK 0xa3 - -/* BlockGroup Elements */ -#define ID_BLOCK 0xa1 -#define ID_BLOCK_ADDITIONS 0x75a1 -#define ID_BLOCK_DURATION 0x9b -#define ID_REFERENCE_BLOCK 0xfb -#define ID_DISCARD_PADDING 0x75a2 - -/* BlockAdditions Elements */ -#define ID_BLOCK_MORE 0xa6 - -/* BlockMore Elements */ -#define ID_BLOCK_ADD_ID 0xee -#define ID_BLOCK_ADDITIONAL 0xa5 - -/* Tracks Elements */ -#define ID_TRACKS 0x1654ae6b -#define ID_TRACK_ENTRY 0xae -#define ID_TRACK_NUMBER 0xd7 -#define ID_TRACK_UID 0x73c5 -#define ID_TRACK_TYPE 0x83 -#define ID_FLAG_ENABLED 0xb9 -#define ID_FLAG_DEFAULT 0x88 -#define ID_FLAG_LACING 0x9c -#define ID_TRACK_TIMECODE_SCALE 0x23314f -#define ID_LANGUAGE 0x22b59c -#define ID_CODEC_ID 0x86 -#define ID_CODEC_PRIVATE 0x63a2 -#define ID_CODEC_DELAY 0x56aa -#define ID_SEEK_PREROLL 0x56bb -#define ID_DEFAULT_DURATION 0x23e383 - -/* Video Elements */ -#define ID_VIDEO 0xe0 -#define ID_STEREO_MODE 0x53b8 -#define ID_ALPHA_MODE 0x53c0 -#define ID_PIXEL_WIDTH 0xb0 -#define ID_PIXEL_HEIGHT 0xba -#define ID_PIXEL_CROP_BOTTOM 0x54aa -#define ID_PIXEL_CROP_TOP 0x54bb -#define ID_PIXEL_CROP_LEFT 0x54cc -#define ID_PIXEL_CROP_RIGHT 0x54dd -#define ID_DISPLAY_WIDTH 0x54b0 -#define ID_DISPLAY_HEIGHT 0x54ba - -/* Audio Elements */ -#define ID_AUDIO 0xe1 -#define ID_SAMPLING_FREQUENCY 0xb5 -#define ID_CHANNELS 0x9f -#define ID_BIT_DEPTH 0x6264 - -/* Cues Elements */ -#define ID_CUES 0x1c53bb6b -#define ID_CUE_POINT 0xbb -#define ID_CUE_TIME 0xb3 -#define ID_CUE_TRACK_POSITIONS 0xb7 -#define ID_CUE_TRACK 0xf7 -#define ID_CUE_CLUSTER_POSITION 0xf1 -#define ID_CUE_BLOCK_NUMBER 0x5378 - -/* Encoding Elements */ -#define ID_CONTENT_ENCODINGS 0x6d80 -#define ID_CONTENT_ENCODING 0x6240 -#define ID_CONTENT_ENCODING_TYPE 0x5033 - -/* Encryption Elements */ -#define ID_CONTENT_ENCRYPTION 0x5035 -#define ID_CONTENT_ENC_ALGO 0x47e1 -#define ID_CONTENT_ENC_KEY_ID 0x47e2 -#define ID_CONTENT_ENC_AES_SETTINGS 0x47e7 -#define ID_AES_SETTINGS_CIPHER_MODE 0x47e8 - -/* EBML Types */ -enum ebml_type_enum { - TYPE_UNKNOWN, - TYPE_MASTER, - TYPE_UINT, - TYPE_FLOAT, - TYPE_STRING, - TYPE_BINARY -}; - -#define LIMIT_STRING (1 << 20) -#define LIMIT_BINARY (1 << 24) -#define LIMIT_BLOCK (1 << 30) -#define LIMIT_FRAME (1 << 28) - -/* Field Flags */ -#define DESC_FLAG_NONE 0 -#define DESC_FLAG_MULTI (1 << 0) -#define DESC_FLAG_SUSPEND (1 << 1) -#define DESC_FLAG_OFFSET (1 << 2) - -/* Block Header Flags */ -#define SIMPLE_BLOCK_FLAGS_KEYFRAME (1 << 7) -#define BLOCK_FLAGS_LACING 6 - -/* Lacing Constants */ -#define LACING_NONE 0 -#define LACING_XIPH 1 -#define LACING_FIXED 2 -#define LACING_EBML 3 - -/* Track Types */ -#define TRACK_TYPE_VIDEO 1 -#define TRACK_TYPE_AUDIO 2 - -/* Track IDs */ -#define TRACK_ID_VP8 "V_VP8" -#define TRACK_ID_VP9 "V_VP9" -#define TRACK_ID_AV1 "V_AV1" -#define TRACK_ID_VORBIS "A_VORBIS" -#define TRACK_ID_OPUS "A_OPUS" -#define TRACK_ID_AVC1 "V_MPEG4/ISO/AVC" -#define TRACK_ID_AAC "A_AAC" - -/* Track Encryption */ -#define CONTENT_ENC_ALGO_AES 5 -#define AES_SETTINGS_CIPHER_CTR 1 - -/* Packet Encryption */ -#define SIGNAL_BYTE_SIZE 1 -#define IV_SIZE 8 -#define NUM_PACKETS_SIZE 1 -#define PACKET_OFFSET_SIZE 4 - -/* Signal Byte */ -#define PACKET_ENCRYPTED 1 -#define ENCRYPTED_BIT_MASK (1 << 0) - -#define PACKET_PARTITIONED 2 -#define PARTITIONED_BIT_MASK (1 << 1) - -enum vint_mask { - MASK_NONE, - MASK_FIRST_BIT -}; - -struct ebml_binary { - unsigned char * data; - size_t length; -}; - -struct ebml_list_node { - struct ebml_list_node * next; - uint64_t id; - void * data; -}; - -struct ebml_list { - struct ebml_list_node * head; - struct ebml_list_node * tail; -}; - -struct ebml_type { - union ebml_value { - uint64_t u; - double f; - int64_t i; - char * s; - struct ebml_binary b; - } v; - enum ebml_type_enum type; - int read; -}; - -/* EBML Definitions */ -struct ebml { - struct ebml_type ebml_version; - struct ebml_type ebml_read_version; - struct ebml_type ebml_max_id_length; - struct ebml_type ebml_max_size_length; - struct ebml_type doctype; - struct ebml_type doctype_version; - struct ebml_type doctype_read_version; -}; - -/* Matroksa Definitions */ -struct seek { - struct ebml_type id; - struct ebml_type position; -}; - -struct seek_head { - struct ebml_list seek; -}; - -struct info { - struct ebml_type timecode_scale; - struct ebml_type duration; -}; - -struct video { - struct ebml_type stereo_mode; - struct ebml_type alpha_mode; - struct ebml_type pixel_width; - struct ebml_type pixel_height; - struct ebml_type pixel_crop_bottom; - struct ebml_type pixel_crop_top; - struct ebml_type pixel_crop_left; - struct ebml_type pixel_crop_right; - struct ebml_type display_width; - struct ebml_type display_height; -}; - -struct audio { - struct ebml_type sampling_frequency; - struct ebml_type channels; - struct ebml_type bit_depth; -}; - -struct content_enc_aes_settings { - struct ebml_type aes_settings_cipher_mode; -}; - -struct content_encryption { - struct ebml_type content_enc_algo; - struct ebml_type content_enc_key_id; - struct ebml_list content_enc_aes_settings; -}; - -struct content_encoding { - struct ebml_type content_encoding_type; - struct ebml_list content_encryption; -}; - -struct content_encodings { - struct ebml_list content_encoding; -}; - -struct track_entry { - struct ebml_type number; - struct ebml_type uid; - struct ebml_type type; - struct ebml_type flag_enabled; - struct ebml_type flag_default; - struct ebml_type flag_lacing; - struct ebml_type track_timecode_scale; - struct ebml_type language; - struct ebml_type codec_id; - struct ebml_type codec_private; - struct ebml_type codec_delay; - struct ebml_type seek_preroll; - struct ebml_type default_duration; - struct video video; - struct audio audio; - struct content_encodings content_encodings; -}; - -struct tracks { - struct ebml_list track_entry; -}; - -struct cue_track_positions { - struct ebml_type track; - struct ebml_type cluster_position; - struct ebml_type block_number; -}; - -struct cue_point { - struct ebml_type time; - struct ebml_list cue_track_positions; -}; - -struct cues { - struct ebml_list cue_point; -}; - -struct segment { - struct ebml_list seek_head; - struct info info; - struct tracks tracks; - struct cues cues; -}; - -/* Misc. */ -struct pool_node { - struct pool_node * next; - void * data; -}; - -struct pool_ctx { - struct pool_node * head; -}; - -struct list_node { - struct list_node * previous; - struct ebml_element_desc * node; - unsigned char * data; -}; - -struct saved_state { - int64_t stream_offset; - uint64_t last_id; - uint64_t last_size; - int last_valid; -}; - -struct frame_encryption { - unsigned char * iv; - size_t length; - uint8_t signal_byte; - uint8_t num_partitions; - uint32_t * partition_offsets; -}; - -struct frame { - unsigned char * data; - size_t length; - struct frame_encryption * frame_encryption; - struct frame * next; -}; - -struct block_additional { - unsigned int id; - unsigned char * data; - size_t length; - struct block_additional * next; -}; - -/* Public (opaque) Structures */ -struct nestegg { - nestegg_io * io; - nestegg_log log; - struct pool_ctx * alloc_pool; - uint64_t last_id; - uint64_t last_size; - int last_valid; - struct list_node * ancestor; - struct ebml ebml; - struct segment segment; - int64_t segment_offset; - unsigned int track_count; - /* Last read cluster. */ - uint64_t cluster_timecode; - int read_cluster_timecode; - struct saved_state saved; -}; - -struct nestegg_packet { - uint64_t track; - uint64_t timecode; - uint64_t duration; - int read_duration; - struct frame * frame; - struct block_additional * block_additional; - int64_t discard_padding; - int read_discard_padding; - int64_t reference_block; - int read_reference_block; - uint8_t keyframe; -}; - -/* Element Descriptor */ -struct ebml_element_desc { - char const * name; - uint64_t id; - enum ebml_type_enum type; - size_t offset; - unsigned int flags; - struct ebml_element_desc * children; - size_t size; - size_t data_offset; -}; - -#define E_FIELD(ID, TYPE, STRUCT, FIELD) \ - { #ID, ID, TYPE, offsetof(STRUCT, FIELD), DESC_FLAG_NONE, NULL, 0, 0 } -#define E_MASTER(ID, TYPE, STRUCT, FIELD) \ - { #ID, ID, TYPE, offsetof(STRUCT, FIELD), DESC_FLAG_MULTI, ne_ ## FIELD ## _elements, \ - sizeof(struct FIELD), 0 } -#define E_SINGLE_MASTER_O(ID, TYPE, STRUCT, FIELD) \ - { #ID, ID, TYPE, offsetof(STRUCT, FIELD), DESC_FLAG_OFFSET, ne_ ## FIELD ## _elements, 0, \ - offsetof(STRUCT, FIELD ## _offset) } -#define E_SINGLE_MASTER(ID, TYPE, STRUCT, FIELD) \ - { #ID, ID, TYPE, offsetof(STRUCT, FIELD), DESC_FLAG_NONE, ne_ ## FIELD ## _elements, 0, 0 } -#define E_SUSPEND(ID, TYPE) \ - { #ID, ID, TYPE, 0, DESC_FLAG_SUSPEND, NULL, 0, 0 } -#define E_LAST \ - { NULL, 0, 0, 0, DESC_FLAG_NONE, NULL, 0, 0 } - -/* EBML Element Lists */ -static struct ebml_element_desc ne_ebml_elements[] = { - E_FIELD(ID_EBML_VERSION, TYPE_UINT, struct ebml, ebml_version), - E_FIELD(ID_EBML_READ_VERSION, TYPE_UINT, struct ebml, ebml_read_version), - E_FIELD(ID_EBML_MAX_ID_LENGTH, TYPE_UINT, struct ebml, ebml_max_id_length), - E_FIELD(ID_EBML_MAX_SIZE_LENGTH, TYPE_UINT, struct ebml, ebml_max_size_length), - E_FIELD(ID_DOCTYPE, TYPE_STRING, struct ebml, doctype), - E_FIELD(ID_DOCTYPE_VERSION, TYPE_UINT, struct ebml, doctype_version), - E_FIELD(ID_DOCTYPE_READ_VERSION, TYPE_UINT, struct ebml, doctype_read_version), - E_LAST -}; - -/* WebM Element Lists */ -static struct ebml_element_desc ne_seek_elements[] = { - E_FIELD(ID_SEEK_ID, TYPE_BINARY, struct seek, id), - E_FIELD(ID_SEEK_POSITION, TYPE_UINT, struct seek, position), - E_LAST -}; - -static struct ebml_element_desc ne_seek_head_elements[] = { - E_MASTER(ID_SEEK, TYPE_MASTER, struct seek_head, seek), - E_LAST -}; - -static struct ebml_element_desc ne_info_elements[] = { - E_FIELD(ID_TIMECODE_SCALE, TYPE_UINT, struct info, timecode_scale), - E_FIELD(ID_DURATION, TYPE_FLOAT, struct info, duration), - E_LAST -}; - -static struct ebml_element_desc ne_video_elements[] = { - E_FIELD(ID_STEREO_MODE, TYPE_UINT, struct video, stereo_mode), - E_FIELD(ID_ALPHA_MODE, TYPE_UINT, struct video, alpha_mode), - E_FIELD(ID_PIXEL_WIDTH, TYPE_UINT, struct video, pixel_width), - E_FIELD(ID_PIXEL_HEIGHT, TYPE_UINT, struct video, pixel_height), - E_FIELD(ID_PIXEL_CROP_BOTTOM, TYPE_UINT, struct video, pixel_crop_bottom), - E_FIELD(ID_PIXEL_CROP_TOP, TYPE_UINT, struct video, pixel_crop_top), - E_FIELD(ID_PIXEL_CROP_LEFT, TYPE_UINT, struct video, pixel_crop_left), - E_FIELD(ID_PIXEL_CROP_RIGHT, TYPE_UINT, struct video, pixel_crop_right), - E_FIELD(ID_DISPLAY_WIDTH, TYPE_UINT, struct video, display_width), - E_FIELD(ID_DISPLAY_HEIGHT, TYPE_UINT, struct video, display_height), - E_LAST -}; - -static struct ebml_element_desc ne_audio_elements[] = { - E_FIELD(ID_SAMPLING_FREQUENCY, TYPE_FLOAT, struct audio, sampling_frequency), - E_FIELD(ID_CHANNELS, TYPE_UINT, struct audio, channels), - E_FIELD(ID_BIT_DEPTH, TYPE_UINT, struct audio, bit_depth), - E_LAST -}; - -static struct ebml_element_desc ne_content_enc_aes_settings_elements[] = { - E_FIELD(ID_AES_SETTINGS_CIPHER_MODE, TYPE_UINT, struct content_enc_aes_settings, aes_settings_cipher_mode), - E_LAST -}; - -static struct ebml_element_desc ne_content_encryption_elements[] = { - E_FIELD(ID_CONTENT_ENC_ALGO, TYPE_UINT, struct content_encryption, content_enc_algo), - E_FIELD(ID_CONTENT_ENC_KEY_ID, TYPE_BINARY, struct content_encryption, content_enc_key_id), - E_MASTER(ID_CONTENT_ENC_AES_SETTINGS, TYPE_MASTER, struct content_encryption, content_enc_aes_settings), - E_LAST -}; - -static struct ebml_element_desc ne_content_encoding_elements[] = { - E_FIELD(ID_CONTENT_ENCODING_TYPE, TYPE_UINT, struct content_encoding, content_encoding_type), - E_MASTER(ID_CONTENT_ENCRYPTION, TYPE_MASTER, struct content_encoding, content_encryption), - E_LAST -}; - -static struct ebml_element_desc ne_content_encodings_elements[] = { - E_MASTER(ID_CONTENT_ENCODING, TYPE_MASTER, struct content_encodings, content_encoding), - E_LAST -}; - -static struct ebml_element_desc ne_track_entry_elements[] = { - E_FIELD(ID_TRACK_NUMBER, TYPE_UINT, struct track_entry, number), - E_FIELD(ID_TRACK_UID, TYPE_UINT, struct track_entry, uid), - E_FIELD(ID_TRACK_TYPE, TYPE_UINT, struct track_entry, type), - E_FIELD(ID_FLAG_ENABLED, TYPE_UINT, struct track_entry, flag_enabled), - E_FIELD(ID_FLAG_DEFAULT, TYPE_UINT, struct track_entry, flag_default), - E_FIELD(ID_FLAG_LACING, TYPE_UINT, struct track_entry, flag_lacing), - E_FIELD(ID_TRACK_TIMECODE_SCALE, TYPE_FLOAT, struct track_entry, track_timecode_scale), - E_FIELD(ID_LANGUAGE, TYPE_STRING, struct track_entry, language), - E_FIELD(ID_CODEC_ID, TYPE_STRING, struct track_entry, codec_id), - E_FIELD(ID_CODEC_PRIVATE, TYPE_BINARY, struct track_entry, codec_private), - E_FIELD(ID_CODEC_DELAY, TYPE_UINT, struct track_entry, codec_delay), - E_FIELD(ID_SEEK_PREROLL, TYPE_UINT, struct track_entry, seek_preroll), - E_FIELD(ID_DEFAULT_DURATION, TYPE_UINT, struct track_entry, default_duration), - E_SINGLE_MASTER(ID_VIDEO, TYPE_MASTER, struct track_entry, video), - E_SINGLE_MASTER(ID_AUDIO, TYPE_MASTER, struct track_entry, audio), - E_SINGLE_MASTER(ID_CONTENT_ENCODINGS, TYPE_MASTER, struct track_entry, content_encodings), - E_LAST -}; - -static struct ebml_element_desc ne_tracks_elements[] = { - E_MASTER(ID_TRACK_ENTRY, TYPE_MASTER, struct tracks, track_entry), - E_LAST -}; - -static struct ebml_element_desc ne_cue_track_positions_elements[] = { - E_FIELD(ID_CUE_TRACK, TYPE_UINT, struct cue_track_positions, track), - E_FIELD(ID_CUE_CLUSTER_POSITION, TYPE_UINT, struct cue_track_positions, cluster_position), - E_FIELD(ID_CUE_BLOCK_NUMBER, TYPE_UINT, struct cue_track_positions, block_number), - E_LAST -}; - -static struct ebml_element_desc ne_cue_point_elements[] = { - E_FIELD(ID_CUE_TIME, TYPE_UINT, struct cue_point, time), - E_MASTER(ID_CUE_TRACK_POSITIONS, TYPE_MASTER, struct cue_point, cue_track_positions), - E_LAST -}; - -static struct ebml_element_desc ne_cues_elements[] = { - E_MASTER(ID_CUE_POINT, TYPE_MASTER, struct cues, cue_point), - E_LAST -}; - -static struct ebml_element_desc ne_segment_elements[] = { - E_MASTER(ID_SEEK_HEAD, TYPE_MASTER, struct segment, seek_head), - E_SINGLE_MASTER(ID_INFO, TYPE_MASTER, struct segment, info), - E_SUSPEND(ID_CLUSTER, TYPE_MASTER), - E_SINGLE_MASTER(ID_TRACKS, TYPE_MASTER, struct segment, tracks), - E_SINGLE_MASTER(ID_CUES, TYPE_MASTER, struct segment, cues), - E_LAST -}; - -static struct ebml_element_desc ne_top_level_elements[] = { - E_SINGLE_MASTER(ID_EBML, TYPE_MASTER, nestegg, ebml), - E_SINGLE_MASTER_O(ID_SEGMENT, TYPE_MASTER, nestegg, segment), - E_LAST -}; - -#undef E_FIELD -#undef E_MASTER -#undef E_SINGLE_MASTER_O -#undef E_SINGLE_MASTER -#undef E_SUSPEND -#undef E_LAST - -static struct pool_ctx * -ne_pool_init(void) -{ - return calloc(1, sizeof(struct pool_ctx)); -} - -static void -ne_pool_destroy(struct pool_ctx * pool) -{ - struct pool_node * node = pool->head; - while (node) { - struct pool_node * old = node; - node = node->next; - free(old->data); - free(old); - } - free(pool); -} - -static void * -ne_pool_alloc(size_t size, struct pool_ctx * pool) -{ - struct pool_node * node; - - node = calloc(1, sizeof(*node)); - if (!node) - return NULL; - - node->data = calloc(1, size); - if (!node->data) { - free(node); - return NULL; - } - - node->next = pool->head; - pool->head = node; - - return node->data; -} - -static void * -ne_alloc(size_t size) -{ - return calloc(1, size); -} - -static int -ne_io_read(nestegg_io * io, void * buffer, size_t length) -{ - return io->read(buffer, length, io->userdata); -} - -static int -ne_io_seek(nestegg_io * io, int64_t offset, int whence) -{ - return io->seek(offset, whence, io->userdata); -} - -static int -ne_io_read_skip(nestegg_io * io, size_t length) -{ - size_t get; - unsigned char buf[8192]; - int r = 1; - - while (length > 0) { - get = length < sizeof(buf) ? length : sizeof(buf); - r = ne_io_read(io, buf, get); - if (r != 1) - break; - length -= get; - } - - return r; -} - -static int64_t -ne_io_tell(nestegg_io * io) -{ - return io->tell(io->userdata); -} - -static int -ne_bare_read_vint(nestegg_io * io, uint64_t * value, uint64_t * length, enum vint_mask maskflag) -{ - int r; - unsigned char b; - size_t maxlen = 8; - unsigned int count = 1, mask = 1 << 7; - - r = ne_io_read(io, &b, 1); - if (r != 1) - return r; - - while (count < maxlen) { - if ((b & mask) != 0) - break; - mask >>= 1; - count += 1; - } - - if (length) - *length = count; - *value = b; - - if (maskflag == MASK_FIRST_BIT) - *value = b & ~mask; - - while (--count) { - r = ne_io_read(io, &b, 1); - if (r != 1) - return r; - *value <<= 8; - *value |= b; - } - - return 1; -} - -static int -ne_read_id(nestegg_io * io, uint64_t * value, uint64_t * length) -{ - return ne_bare_read_vint(io, value, length, MASK_NONE); -} - -static int -ne_read_vint(nestegg_io * io, uint64_t * value, uint64_t * length) -{ - return ne_bare_read_vint(io, value, length, MASK_FIRST_BIT); -} - -static int -ne_read_svint(nestegg_io * io, int64_t * value, uint64_t * length) -{ - int r; - uint64_t uvalue; - uint64_t ulength; - int64_t svint_subtr[] = { - 0x3f, 0x1fff, - 0xfffff, 0x7ffffff, - 0x3ffffffffLL, 0x1ffffffffffLL, - 0xffffffffffffLL, 0x7fffffffffffffLL - }; - - r = ne_bare_read_vint(io, &uvalue, &ulength, MASK_FIRST_BIT); - if (r != 1) - return r; - *value = uvalue - svint_subtr[ulength - 1]; - if (length) - *length = ulength; - return r; -} - -static int -ne_read_uint(nestegg_io * io, uint64_t * val, uint64_t length) -{ - unsigned char b; - int r; - - if (length == 0 || length > 8) - return -1; - r = ne_io_read(io, &b, 1); - if (r != 1) - return r; - *val = b; - while (--length) { - r = ne_io_read(io, &b, 1); - if (r != 1) - return r; - *val <<= 8; - *val |= b; - } - return 1; -} - -static int -ne_read_int(nestegg_io * io, int64_t * val, uint64_t length) -{ - int r; - uint64_t uval, base; - - r = ne_read_uint(io, &uval, length); - if (r != 1) - return r; - - if (length < sizeof(int64_t)) { - base = 1; - base <<= length * 8 - 1; - if (uval >= base) { - base = 1; - base <<= length * 8; - } else { - base = 0; - } - *val = uval - base; - } else { - *val = (int64_t) uval; - } - - return 1; -} - -static int -ne_read_float(nestegg_io * io, double * val, uint64_t length) -{ - union { - uint64_t u; - float f; - double d; - } value; - int r; - - /* Length == 10 not implemented. */ - if (length != 4 && length != 8) - return -1; - r = ne_read_uint(io, &value.u, length); - if (r != 1) - return r; - if (length == 4) - *val = value.f; - else - *val = value.d; - return 1; -} - -static int -ne_read_string(nestegg * ctx, char ** val, uint64_t length) -{ - char * str; - int r; - - if (length > LIMIT_STRING) - return -1; - str = ne_pool_alloc(length + 1, ctx->alloc_pool); - if (!str) - return -1; - if (length) { - r = ne_io_read(ctx->io, (unsigned char *) str, length); - if (r != 1) - return r; - } - str[length] = '\0'; - *val = str; - return 1; -} - -static int -ne_read_binary(nestegg * ctx, struct ebml_binary * val, uint64_t length) -{ - if (length == 0 || length > LIMIT_BINARY) - return -1; - val->data = ne_pool_alloc(length, ctx->alloc_pool); - if (!val->data) - return -1; - val->length = length; - return ne_io_read(ctx->io, val->data, length); -} - -static int -ne_get_uint(struct ebml_type type, uint64_t * value) -{ - if (!type.read) - return -1; - - assert(type.type == TYPE_UINT); - - *value = type.v.u; - - return 0; -} - -static int -ne_get_float(struct ebml_type type, double * value) -{ - if (!type.read) - return -1; - - assert(type.type == TYPE_FLOAT); - - *value = type.v.f; - - return 0; -} - -static int -ne_get_string(struct ebml_type type, char ** value) -{ - if (!type.read) - return -1; - - assert(type.type == TYPE_STRING); - - *value = type.v.s; - - return 0; -} - -static int -ne_get_binary(struct ebml_type type, struct ebml_binary * value) -{ - if (!type.read) - return -1; - - assert(type.type == TYPE_BINARY); - - *value = type.v.b; - - return 0; -} - -static int -ne_is_ancestor_element(uint64_t id, struct list_node * ancestor) -{ - struct ebml_element_desc * element; - - for (; ancestor; ancestor = ancestor->previous) - for (element = ancestor->node; element->id; ++element) - if (element->id == id) - return 1; - - return 0; -} - -static struct ebml_element_desc * -ne_find_element(uint64_t id, struct ebml_element_desc * elements) -{ - struct ebml_element_desc * element; - - for (element = elements; element->id; ++element) - if (element->id == id) - return element; - - return NULL; -} - -static int -ne_ctx_push(nestegg * ctx, struct ebml_element_desc * ancestor, void * data) -{ - struct list_node * item; - - item = ne_alloc(sizeof(*item)); - if (!item) - return -1; - item->previous = ctx->ancestor; - item->node = ancestor; - item->data = data; - ctx->ancestor = item; - return 0; -} - -static void -ne_ctx_pop(nestegg * ctx) -{ - struct list_node * item; - - item = ctx->ancestor; - ctx->ancestor = item->previous; - free(item); -} - -static int -ne_ctx_save(nestegg * ctx, struct saved_state * s) -{ - s->stream_offset = ne_io_tell(ctx->io); - if (s->stream_offset < 0) - return -1; - s->last_id = ctx->last_id; - s->last_size = ctx->last_size; - s->last_valid = ctx->last_valid; - return 0; -} - -static int -ne_ctx_restore(nestegg * ctx, struct saved_state * s) -{ - int r; - - if (s->stream_offset < 0) - return -1; - r = ne_io_seek(ctx->io, s->stream_offset, NESTEGG_SEEK_SET); - if (r != 0) - return -1; - ctx->last_id = s->last_id; - ctx->last_size = s->last_size; - ctx->last_valid = s->last_valid; - return 0; -} - -static int -ne_peek_element(nestegg * ctx, uint64_t * id, uint64_t * size) -{ - int r; - - if (ctx->last_valid) { - if (id) - *id = ctx->last_id; - if (size) - *size = ctx->last_size; - return 1; - } - - r = ne_read_id(ctx->io, &ctx->last_id, NULL); - if (r != 1) - return r; - - r = ne_read_vint(ctx->io, &ctx->last_size, NULL); - if (r != 1) - return r; - - if (id) - *id = ctx->last_id; - if (size) - *size = ctx->last_size; - - ctx->last_valid = 1; - - return 1; -} - -static int -ne_read_element(nestegg * ctx, uint64_t * id, uint64_t * size) -{ - int r; - - r = ne_peek_element(ctx, id, size); - if (r != 1) - return r; - - ctx->last_valid = 0; - - return 1; -} - -static int -ne_read_master(nestegg * ctx, struct ebml_element_desc * desc) -{ - struct ebml_list * list; - struct ebml_list_node * node, * oldtail; - - assert(desc->type == TYPE_MASTER && desc->flags & DESC_FLAG_MULTI); - - ctx->log(ctx, NESTEGG_LOG_DEBUG, "multi master element %llx (%s)", - desc->id, desc->name); - - list = (struct ebml_list *) (ctx->ancestor->data + desc->offset); - - node = ne_pool_alloc(sizeof(*node), ctx->alloc_pool); - if (!node) - return -1; - node->id = desc->id; - node->data = ne_pool_alloc(desc->size, ctx->alloc_pool); - if (!node->data) - return -1; - - oldtail = list->tail; - if (oldtail) - oldtail->next = node; - list->tail = node; - if (!list->head) - list->head = node; - - ctx->log(ctx, NESTEGG_LOG_DEBUG, " -> using data %p", node->data); - - if (ne_ctx_push(ctx, desc->children, node->data) < 0) - return -1; - - return 0; -} - -static int -ne_read_single_master(nestegg * ctx, struct ebml_element_desc * desc) -{ - assert(desc->type == TYPE_MASTER && !(desc->flags & DESC_FLAG_MULTI)); - - ctx->log(ctx, NESTEGG_LOG_DEBUG, "single master element %llx (%s)", - desc->id, desc->name); - ctx->log(ctx, NESTEGG_LOG_DEBUG, " -> using data %p (%u)", - ctx->ancestor->data + desc->offset, desc->offset); - - return ne_ctx_push(ctx, desc->children, ctx->ancestor->data + desc->offset); -} - -static int -ne_read_simple(nestegg * ctx, struct ebml_element_desc * desc, size_t length) -{ - struct ebml_type * storage; - int r = -1; - - storage = (struct ebml_type *) (ctx->ancestor->data + desc->offset); - - if (storage->read) { - ctx->log(ctx, NESTEGG_LOG_DEBUG, "element %llx (%s) already read, skipping %u", - desc->id, desc->name, length); - return ne_io_read_skip(ctx->io, length); - } - - storage->type = desc->type; - - ctx->log(ctx, NESTEGG_LOG_DEBUG, "element %llx (%s) -> %p (%u)", - desc->id, desc->name, storage, desc->offset); - - switch (desc->type) { - case TYPE_UINT: - r = ne_read_uint(ctx->io, &storage->v.u, length); - break; - case TYPE_FLOAT: - r = ne_read_float(ctx->io, &storage->v.f, length); - break; - case TYPE_STRING: - r = ne_read_string(ctx, &storage->v.s, length); - break; - case TYPE_BINARY: - r = ne_read_binary(ctx, &storage->v.b, length); - break; - case TYPE_MASTER: - case TYPE_UNKNOWN: - default: - assert(0); - break; - } - - if (r == 1) - storage->read = 1; - - return r; -} - -static int -ne_parse(nestegg * ctx, struct ebml_element_desc * top_level, int64_t max_offset) -{ - int r; - int64_t * data_offset; - uint64_t id, size, peeked_id; - struct ebml_element_desc * element; - - assert(ctx->ancestor); - - for (;;) { - if (max_offset > 0 && ne_io_tell(ctx->io) >= max_offset) { - /* Reached end of offset allowed for parsing - return gracefully */ - r = 1; - break; - } - r = ne_peek_element(ctx, &id, &size); - if (r != 1) - break; - peeked_id = id; - - element = ne_find_element(id, ctx->ancestor->node); - if (element) { - if (element->flags & DESC_FLAG_SUSPEND) { - assert(element->id == ID_CLUSTER && element->type == TYPE_MASTER); - ctx->log(ctx, NESTEGG_LOG_DEBUG, "suspend parse at %llx", id); - r = 1; - break; - } - - r = ne_read_element(ctx, &id, &size); - if (r != 1) - break; - assert(id == peeked_id); - - if (element->flags & DESC_FLAG_OFFSET) { - data_offset = (int64_t *) (ctx->ancestor->data + element->data_offset); - *data_offset = ne_io_tell(ctx->io); - if (*data_offset < 0) { - r = -1; - break; - } - } - - if (element->type == TYPE_MASTER) { - if (element->flags & DESC_FLAG_MULTI) { - if (ne_read_master(ctx, element) < 0) - break; - } else { - if (ne_read_single_master(ctx, element) < 0) - break; - } - continue; - } else { - r = ne_read_simple(ctx, element, size); - if (r < 0) - break; - } - } else if (ne_is_ancestor_element(id, ctx->ancestor->previous)) { - ctx->log(ctx, NESTEGG_LOG_DEBUG, "parent element %llx", id); - if (top_level && ctx->ancestor->node == top_level) { - ctx->log(ctx, NESTEGG_LOG_DEBUG, "*** parse about to back up past top_level"); - r = 1; - break; - } - ne_ctx_pop(ctx); - } else { - r = ne_read_element(ctx, &id, &size); - if (r != 1) - break; - - if (id != ID_VOID && id != ID_CRC32) - ctx->log(ctx, NESTEGG_LOG_DEBUG, "unknown element %llx", id); - r = ne_io_read_skip(ctx->io, size); - if (r != 1) - break; - } - } - - if (r != 1) - while (ctx->ancestor) - ne_ctx_pop(ctx); - - return r; -} - -static int -ne_read_block_encryption(nestegg * ctx, struct track_entry const * entry, - uint64_t * encoding_type, uint64_t * encryption_algo, - uint64_t * encryption_mode) -{ - struct content_encoding * encoding; - struct content_encryption * encryption; - struct content_enc_aes_settings * aes_settings; - - *encoding_type = 0; - if (entry->content_encodings.content_encoding.head) { - encoding = entry->content_encodings.content_encoding.head->data; - if (ne_get_uint(encoding->content_encoding_type, encoding_type) != 0) - return -1; - - if (*encoding_type == NESTEGG_ENCODING_ENCRYPTION) { - /* Metadata states content is encrypted */ - if (!encoding->content_encryption.head) - return -1; - - encryption = encoding->content_encryption.head->data; - if (ne_get_uint(encryption->content_enc_algo, encryption_algo) != 0) { - ctx->log(ctx, NESTEGG_LOG_ERROR, "No ContentEncAlgo element found"); - return -1; - } - - if (*encryption_algo != CONTENT_ENC_ALGO_AES) { - ctx->log(ctx, NESTEGG_LOG_ERROR, "Disallowed ContentEncAlgo used"); - return -1; - } - - if (!encryption->content_enc_aes_settings.head) { - ctx->log(ctx, NESTEGG_LOG_ERROR, "No ContentEncAESSettings element found"); - return -1; - } - - aes_settings = encryption->content_enc_aes_settings.head->data; - *encryption_mode = AES_SETTINGS_CIPHER_CTR; - ne_get_uint(aes_settings->aes_settings_cipher_mode, encryption_mode); - - if (*encryption_mode != AES_SETTINGS_CIPHER_CTR) { - ctx->log(ctx, NESTEGG_LOG_ERROR, "Disallowed AESSettingsCipherMode used"); - return -1; - } - } - } - return 1; -} - -static int -ne_read_xiph_lace_value(nestegg_io * io, uint64_t * value, size_t * consumed) -{ - int r; - uint64_t lace; - - r = ne_read_uint(io, &lace, 1); - if (r != 1) - return r; - *consumed += 1; - - *value = lace; - while (lace == 255) { - r = ne_read_uint(io, &lace, 1); - if (r != 1) - return r; - *consumed += 1; - *value += lace; - } - - return 1; -} - -static int -ne_read_xiph_lacing(nestegg_io * io, size_t block, size_t * read, uint64_t n, uint64_t * sizes) -{ - int r; - size_t i = 0; - uint64_t sum = 0; - - while (--n) { - r = ne_read_xiph_lace_value(io, &sizes[i], read); - if (r != 1) - return r; - sum += sizes[i]; - i += 1; - } - - if (*read + sum > block) - return -1; - - /* Last frame is the remainder of the block. */ - sizes[i] = block - *read - sum; - return 1; -} - -static int -ne_read_ebml_lacing(nestegg_io * io, size_t block, size_t * read, uint64_t n, uint64_t * sizes) -{ - int r; - uint64_t lace, sum, length; - int64_t slace; - size_t i = 0; - - r = ne_read_vint(io, &lace, &length); - if (r != 1) - return r; - *read += length; - - sizes[i] = lace; - sum = sizes[i]; - - i += 1; - n -= 1; - - while (--n) { - r = ne_read_svint(io, &slace, &length); - if (r != 1) - return r; - *read += length; - sizes[i] = sizes[i - 1] + slace; - sum += sizes[i]; - i += 1; - } - - if (*read + sum > block) - return -1; - - /* Last frame is the remainder of the block. */ - sizes[i] = block - *read - sum; - return 1; -} - -static uint64_t -ne_get_timecode_scale(nestegg * ctx) -{ - uint64_t scale; - - if (ne_get_uint(ctx->segment.info.timecode_scale, &scale) != 0) - scale = 1000000; - - return scale; -} - -static int -ne_map_track_number_to_index(nestegg * ctx, - unsigned int track_number, - unsigned int * track_index) -{ - struct ebml_list_node * node; - struct track_entry * t_entry; - uint64_t t_number = 0; - - if (!track_index) - return -1; - *track_index = 0; - - if (track_number == 0) - return -1; - - node = ctx->segment.tracks.track_entry.head; - while (node) { - assert(node->id == ID_TRACK_ENTRY); - t_entry = node->data; - if (ne_get_uint(t_entry->number, &t_number) != 0) - return -1; - if (t_number == track_number) - return 0; - *track_index += 1; - node = node->next; - } - - return -1; -} - -static struct track_entry * -ne_find_track_entry(nestegg * ctx, unsigned int track) -{ - struct ebml_list_node * node; - unsigned int tracks = 0; - - node = ctx->segment.tracks.track_entry.head; - while (node) { - assert(node->id == ID_TRACK_ENTRY); - if (track == tracks) - return node->data; - tracks += 1; - node = node->next; - } - - return NULL; -} - -static struct frame * -ne_alloc_frame(void) -{ - struct frame * f = ne_alloc(sizeof(*f)); - - if (!f) - return NULL; - - f->data = NULL; - f->length = 0; - f->frame_encryption = NULL; - f->next = NULL; - - return f; -} - -static struct frame_encryption * -ne_alloc_frame_encryption(void) -{ - struct frame_encryption * f = ne_alloc(sizeof(*f)); - - if (!f) - return NULL; - - f->iv = NULL; - f->length = 0; - f->signal_byte = 0; - f->num_partitions = 0; - f->partition_offsets = NULL; - - return f; -} - -static void -ne_free_frame(struct frame * f) -{ - if (f->frame_encryption) { - free(f->frame_encryption->iv); - free(f->frame_encryption->partition_offsets); - } - - free(f->frame_encryption); - free(f->data); - free(f); -} - -static int -ne_read_block(nestegg * ctx, uint64_t block_id, uint64_t block_size, nestegg_packet ** data) -{ - int r; - int64_t timecode, abs_timecode; - nestegg_packet * pkt; - struct frame * f, * last; - struct track_entry * entry; - double track_scale; - uint64_t track_number, length, frame_sizes[256], cluster_tc, flags, frames, tc_scale, total, - encoding_type, encryption_algo, encryption_mode; - unsigned int i, lacing, track; - uint8_t signal_byte, keyframe = NESTEGG_PACKET_HAS_KEYFRAME_UNKNOWN, j = 0; - size_t consumed = 0, data_size, encryption_size; - - *data = NULL; - - if (block_size > LIMIT_BLOCK) - return -1; - - r = ne_read_vint(ctx->io, &track_number, &length); - if (r != 1) - return r; - - if (track_number == 0) - return -1; - - consumed += length; - - r = ne_read_int(ctx->io, &timecode, 2); - if (r != 1) - return r; - - consumed += 2; - - r = ne_read_uint(ctx->io, &flags, 1); - if (r != 1) - return r; - - consumed += 1; - - frames = 0; - - /* Simple blocks have an explicit flag for if the contents a keyframes*/ - if (block_id == ID_SIMPLE_BLOCK) - keyframe = (flags & SIMPLE_BLOCK_FLAGS_KEYFRAME) == SIMPLE_BLOCK_FLAGS_KEYFRAME ? - NESTEGG_PACKET_HAS_KEYFRAME_TRUE : - NESTEGG_PACKET_HAS_KEYFRAME_FALSE; - - /* Flags are different between Block and SimpleBlock, but lacing is - encoded the same way. */ - lacing = (flags & BLOCK_FLAGS_LACING) >> 1; - - switch (lacing) { - case LACING_NONE: - frames = 1; - break; - case LACING_XIPH: - case LACING_FIXED: - case LACING_EBML: - r = ne_read_uint(ctx->io, &frames, 1); - if (r != 1) - return r; - consumed += 1; - frames += 1; - break; - default: - assert(0); - return -1; - } - - if (frames > 256) - return -1; - - switch (lacing) { - case LACING_NONE: - frame_sizes[0] = block_size - consumed; - break; - case LACING_XIPH: - if (frames == 1) - return -1; - r = ne_read_xiph_lacing(ctx->io, block_size, &consumed, frames, frame_sizes); - if (r != 1) - return r; - break; - case LACING_FIXED: - if ((block_size - consumed) % frames) - return -1; - for (i = 0; i < frames; ++i) - frame_sizes[i] = (block_size - consumed) / frames; - break; - case LACING_EBML: - if (frames == 1) - return -1; - r = ne_read_ebml_lacing(ctx->io, block_size, &consumed, frames, frame_sizes); - if (r != 1) - return r; - break; - default: - assert(0); - return -1; - } - - /* Sanity check unlaced frame sizes against total block size. */ - total = consumed; - for (i = 0; i < frames; ++i) - total += frame_sizes[i]; - if (total > block_size) - return -1; - - if (ne_map_track_number_to_index(ctx, track_number, &track) != 0) - return -1; - - entry = ne_find_track_entry(ctx, track); - if (!entry) - return -1; - - r = ne_read_block_encryption(ctx, entry, &encoding_type, &encryption_algo, &encryption_mode); - if (r != 1) - return r; - - /* Encryption does not support lacing */ - if (lacing != LACING_NONE && encoding_type == NESTEGG_ENCODING_ENCRYPTION) { - ctx->log(ctx, NESTEGG_LOG_ERROR, "Encrypted blocks may not also be laced"); - return -1; - } - - track_scale = 1.0; - - tc_scale = ne_get_timecode_scale(ctx); - if (tc_scale == 0) - return -1; - - if (!ctx->read_cluster_timecode) - return -1; - cluster_tc = ctx->cluster_timecode; - - abs_timecode = timecode + cluster_tc; - if (abs_timecode < 0) { - /* Ignore the spec and negative timestamps */ - ctx->log(ctx, NESTEGG_LOG_WARNING, "ignoring negative timecode: %lld", abs_timecode); - abs_timecode = 0; - } - - pkt = ne_alloc(sizeof(*pkt)); - if (!pkt) - return -1; - pkt->track = track; - pkt->timecode = abs_timecode * tc_scale * track_scale; - pkt->keyframe = keyframe; - - ctx->log(ctx, NESTEGG_LOG_DEBUG, "%sblock t %lld pts %f f %llx frames: %llu", - block_id == ID_BLOCK ? "" : "simple", pkt->track, pkt->timecode / 1e9, flags, frames); - - last = NULL; - for (i = 0; i < frames; ++i) { - if (frame_sizes[i] > LIMIT_FRAME) { - nestegg_free_packet(pkt); - return -1; - } - f = ne_alloc_frame(); - if (!f) { - nestegg_free_packet(pkt); - return -1; - } - /* Parse encryption */ - if (encoding_type == NESTEGG_ENCODING_ENCRYPTION) { - r = ne_io_read(ctx->io, &signal_byte, SIGNAL_BYTE_SIZE); - if (r != 1) { - ne_free_frame(f); - nestegg_free_packet(pkt); - return r; - } - f->frame_encryption = ne_alloc_frame_encryption(); - if (!f->frame_encryption) { - ne_free_frame(f); - nestegg_free_packet(pkt); - return -1; - } - f->frame_encryption->signal_byte = signal_byte; - if ((signal_byte & ENCRYPTED_BIT_MASK) == PACKET_ENCRYPTED) { - f->frame_encryption->iv = ne_alloc(IV_SIZE); - if (!f->frame_encryption->iv) { - ne_free_frame(f); - nestegg_free_packet(pkt); - return -1; - } - r = ne_io_read(ctx->io, f->frame_encryption->iv, IV_SIZE); - if (r != 1) { - ne_free_frame(f); - nestegg_free_packet(pkt); - return r; - } - f->frame_encryption->length = IV_SIZE; - encryption_size = SIGNAL_BYTE_SIZE + IV_SIZE; - - if ((signal_byte & PARTITIONED_BIT_MASK) == PACKET_PARTITIONED) { - r = ne_io_read(ctx->io, &f->frame_encryption->num_partitions, NUM_PACKETS_SIZE); - if (r != 1) { - ne_free_frame(f); - nestegg_free_packet(pkt); - return r; - } - - encryption_size += NUM_PACKETS_SIZE + f->frame_encryption->num_partitions * PACKET_OFFSET_SIZE; - f->frame_encryption->partition_offsets = ne_alloc(f->frame_encryption->num_partitions * PACKET_OFFSET_SIZE); - - for (j = 0; j < f->frame_encryption->num_partitions; ++j) { - uint64_t value = 0; - r = ne_read_uint(ctx->io, &value, PACKET_OFFSET_SIZE); - if (r != 1) { - break; - } - - f->frame_encryption->partition_offsets[j] = (uint32_t) value; - } - - /* If any of the partition offsets did not return 1, then fail. */ - if (j != f->frame_encryption->num_partitions) { - ne_free_frame(f); - nestegg_free_packet(pkt); - return r; - } - } - } else { - encryption_size = SIGNAL_BYTE_SIZE; - } - } else { - encryption_size = 0; - } - if (encryption_size > frame_sizes[i]) { - ne_free_frame(f); - nestegg_free_packet(pkt); - return -1; - } - data_size = frame_sizes[i] - encryption_size; - /* Encryption parsed */ - f->data = ne_alloc(data_size); - if (!f->data) { - ne_free_frame(f); - nestegg_free_packet(pkt); - return -1; - } - f->length = data_size; - r = ne_io_read(ctx->io, f->data, data_size); - if (r != 1) { - ne_free_frame(f); - nestegg_free_packet(pkt); - return r; - } - - if (!last) - pkt->frame = f; - else - last->next = f; - last = f; - } - - *data = pkt; - - return 1; -} - -static int -ne_read_block_additions(nestegg * ctx, uint64_t block_size, struct block_additional ** pkt_block_additional) -{ - int r; - uint64_t id, size, data_size; - int64_t block_additions_end, block_more_end; - void * data; - int has_data; - struct block_additional * block_additional; - uint64_t add_id; - - assert(*pkt_block_additional == NULL); - - block_additions_end = ne_io_tell(ctx->io) + block_size; - - while (ne_io_tell(ctx->io) < block_additions_end) { - add_id = 1; - data = NULL; - has_data = 0; - data_size = 0; - r = ne_read_element(ctx, &id, &size); - if (r != 1) - return r; - - if (id != ID_BLOCK_MORE) { - /* We don't know what this element is, so skip over it */ - if (id != ID_VOID && id != ID_CRC32) - ctx->log(ctx, NESTEGG_LOG_DEBUG, - "unknown element %llx in BlockAdditions", id); - r = ne_io_read_skip(ctx->io, size); - if (r != 1) - return r; - continue; - } - - block_more_end = ne_io_tell(ctx->io) + size; - - while (ne_io_tell(ctx->io) < block_more_end) { - r = ne_read_element(ctx, &id, &size); - if (r != 1) { - free(data); - return r; - } - - if (id == ID_BLOCK_ADD_ID) { - r = ne_read_uint(ctx->io, &add_id, size); - if (r != 1) { - free(data); - return r; - } - - if (add_id == 0) { - ctx->log(ctx, NESTEGG_LOG_ERROR, "Disallowed BlockAddId 0 used"); - free(data); - return -1; - } - } else if (id == ID_BLOCK_ADDITIONAL) { - if (has_data) { - /* BlockAdditional is supposed to only occur once in a - BlockMore. */ - ctx->log(ctx, NESTEGG_LOG_ERROR, - "Multiple BlockAdditional elements in a BlockMore"); - free(data); - return -1; - } - - has_data = 1; - data_size = size; - if (data_size != 0 && data_size < LIMIT_FRAME) { - data = ne_alloc(data_size); - if (!data) - return -1; - r = ne_io_read(ctx->io, data, data_size); - if (r != 1) { - free(data); - return r; - } - } - } else { - /* We don't know what this element is, so skip over it */ - if (id != ID_VOID && id != ID_CRC32) - ctx->log(ctx, NESTEGG_LOG_DEBUG, - "unknown element %llx in BlockMore", id); - r = ne_io_read_skip(ctx->io, size); - if (r != 1) { - free(data); - return r; - } - } - } - - if (has_data == 0) { - ctx->log(ctx, NESTEGG_LOG_ERROR, - "No BlockAdditional element in a BlockMore"); - return -1; - } - - block_additional = ne_alloc(sizeof(*block_additional)); - block_additional->next = *pkt_block_additional; - block_additional->id = add_id; - block_additional->data = data; - block_additional->length = data_size; - *pkt_block_additional = block_additional; - } - - return 1; -} - -static uint64_t -ne_buf_read_id(unsigned char const * p, size_t length) -{ - uint64_t id = 0; - - while (length--) { - id <<= 8; - id |= *p++; - } - - return id; -} - -static struct seek * -ne_find_seek_for_id(struct ebml_list_node * seek_head, uint64_t id) -{ - struct ebml_list * head; - struct ebml_list_node * seek; - struct ebml_binary binary_id; - struct seek * s; - - while (seek_head) { - assert(seek_head->id == ID_SEEK_HEAD); - head = seek_head->data; - seek = head->head; - - while (seek) { - assert(seek->id == ID_SEEK); - s = seek->data; - - if (ne_get_binary(s->id, &binary_id) == 0 && - ne_buf_read_id(binary_id.data, binary_id.length) == id) - return s; - - seek = seek->next; - } - - seek_head = seek_head->next; - } - - return NULL; -} - -static struct cue_track_positions * -ne_find_cue_position_for_track(nestegg * ctx, struct ebml_list_node * node, unsigned int track) -{ - struct cue_track_positions * pos = NULL; - uint64_t track_number; - unsigned int t; - - while (node) { - assert(node->id == ID_CUE_TRACK_POSITIONS); - pos = node->data; - if (ne_get_uint(pos->track, &track_number) != 0) - return NULL; - - if (ne_map_track_number_to_index(ctx, track_number, &t) != 0) - return NULL; - - if (t == track) - return pos; - - node = node->next; - } - - return NULL; -} - -static struct cue_point * -ne_find_cue_point_for_tstamp(nestegg * ctx, struct ebml_list_node * cue_point, unsigned int track, uint64_t scale, uint64_t tstamp) -{ - uint64_t time; - struct cue_point * c, * prev = NULL; - - while (cue_point) { - assert(cue_point->id == ID_CUE_POINT); - c = cue_point->data; - - if (!prev) - prev = c; - - if (ne_get_uint(c->time, &time) == 0 && time * scale > tstamp) - break; - - if (ne_find_cue_position_for_track(ctx, c->cue_track_positions.head, track) != NULL) - prev = c; - - cue_point = cue_point->next; - } - - return prev; -} - -static void -ne_null_log_callback(nestegg * ctx, unsigned int severity, char const * fmt, ...) -{ - if (ctx && severity && fmt) - return; -} - -static int -ne_init_cue_points(nestegg * ctx, int64_t max_offset) -{ - int r; - struct ebml_list_node * node = ctx->segment.cues.cue_point.head; - struct seek * found; - uint64_t seek_pos, id; - struct saved_state state; - - /* If there are no cues loaded, check for cues element in the seek head - and load it. */ - if (!node) { - found = ne_find_seek_for_id(ctx->segment.seek_head.head, ID_CUES); - if (!found) - return -1; - - if (ne_get_uint(found->position, &seek_pos) != 0) - return -1; - - /* Save old parser state. */ - r = ne_ctx_save(ctx, &state); - if (r != 0) - return -1; - - /* Seek and set up parser state for segment-level element (Cues). */ - r = ne_io_seek(ctx->io, ctx->segment_offset + seek_pos, NESTEGG_SEEK_SET); - if (r != 0) - return -1; - ctx->last_valid = 0; - - r = ne_read_element(ctx, &id, NULL); - if (r != 1) - return -1; - - if (id != ID_CUES) - return -1; - - assert(ctx->ancestor == NULL); - if (ne_ctx_push(ctx, ne_top_level_elements, ctx) < 0) - return -1; - if (ne_ctx_push(ctx, ne_segment_elements, &ctx->segment) < 0) - return -1; - if (ne_ctx_push(ctx, ne_cues_elements, &ctx->segment.cues) < 0) - return -1; - /* parser will run until end of cues element. */ - ctx->log(ctx, NESTEGG_LOG_DEBUG, "seek: parsing cue elements"); - r = ne_parse(ctx, ne_cues_elements, max_offset); - while (ctx->ancestor) - ne_ctx_pop(ctx); - - /* Reset parser state to original state and seek back to old position. */ - if (ne_ctx_restore(ctx, &state) != 0) - return -1; - - if (r < 0) - return -1; - - node = ctx->segment.cues.cue_point.head; - if (!node) - return -1; - } - - return 0; -} - -/* Three functions that implement the nestegg_io interface, operating on a - io_buffer. */ -struct io_buffer { - unsigned char const * buffer; - size_t length; - int64_t offset; -}; - -static int -ne_buffer_read(void * buffer, size_t length, void * userdata) -{ - struct io_buffer * iob = userdata; - size_t available = iob->length - iob->offset; - - if (available == 0) - return 0; - - if (available < length) - return -1; - - memcpy(buffer, iob->buffer + iob->offset, length); - iob->offset += length; - - return 1; -} - -static int -ne_buffer_seek(int64_t offset, int whence, void * userdata) -{ - struct io_buffer * iob = userdata; - int64_t o = iob->offset; - - switch(whence) { - case NESTEGG_SEEK_SET: - o = offset; - break; - case NESTEGG_SEEK_CUR: - o += offset; - break; - case NESTEGG_SEEK_END: - o = iob->length + offset; - break; - } - - if (o < 0 || o > (int64_t) iob->length) - return -1; - - iob->offset = o; - return 0; -} - -static int64_t -ne_buffer_tell(void * userdata) -{ - struct io_buffer * iob = userdata; - return iob->offset; -} - -static int -ne_context_new(nestegg ** context, nestegg_io io, nestegg_log callback) -{ - nestegg * ctx; - - if (!(io.read && io.seek && io.tell)) - return -1; - - ctx = ne_alloc(sizeof(*ctx)); - if (!ctx) - return -1; - - ctx->io = ne_alloc(sizeof(*ctx->io)); - if (!ctx->io) { - nestegg_destroy(ctx); - return -1; - } - *ctx->io = io; - ctx->log = callback; - ctx->alloc_pool = ne_pool_init(); - if (!ctx->alloc_pool) { - nestegg_destroy(ctx); - return -1; - } - - if (!ctx->log) - ctx->log = ne_null_log_callback; - - *context = ctx; - return 0; -} - -static int -ne_match_webm(nestegg_io io, int64_t max_offset) -{ - int r; - uint64_t id; - char * doctype; - nestegg * ctx; - - if (ne_context_new(&ctx, io, NULL) != 0) - return -1; - - r = ne_peek_element(ctx, &id, NULL); - if (r != 1) { - nestegg_destroy(ctx); - return 0; - } - - if (id != ID_EBML) { - nestegg_destroy(ctx); - return 0; - } - - ne_ctx_push(ctx, ne_top_level_elements, ctx); - - /* we don't check the return value of ne_parse, that might fail because - max_offset is not on a valid element end point. We only want to check - the EBML ID and that the doctype is "webm". */ - ne_parse(ctx, NULL, max_offset); - while (ctx->ancestor) - ne_ctx_pop(ctx); - - if (ne_get_string(ctx->ebml.doctype, &doctype) != 0 || - strcmp(doctype, "webm") != 0) { - nestegg_destroy(ctx); - return 0; - } - - nestegg_destroy(ctx); - - return 1; -} - -static void -ne_free_block_additions(struct block_additional * block_additional) -{ - while (block_additional) { - struct block_additional * tmp = block_additional; - block_additional = block_additional->next; - free(tmp->data); - free(tmp); - } -} - -int -nestegg_init(nestegg ** context, nestegg_io io, nestegg_log callback, int64_t max_offset) -{ - int r; - uint64_t id, version, docversion; - struct ebml_list_node * track; - char * doctype; - nestegg * ctx; - - if (ne_context_new(&ctx, io, callback) != 0) - return -1; - - r = ne_peek_element(ctx, &id, NULL); - if (r != 1) { - nestegg_destroy(ctx); - return -1; - } - - if (id != ID_EBML) { - nestegg_destroy(ctx); - return -1; - } - - ctx->log(ctx, NESTEGG_LOG_DEBUG, "ctx %p", ctx); - - ne_ctx_push(ctx, ne_top_level_elements, ctx); - - r = ne_parse(ctx, NULL, max_offset); - while (ctx->ancestor) - ne_ctx_pop(ctx); - - if (r != 1) { - nestegg_destroy(ctx); - return -1; - } - - if (ne_get_uint(ctx->ebml.ebml_read_version, &version) != 0) - version = 1; - if (version != 1) { - nestegg_destroy(ctx); - return -1; - } - - if (ne_get_string(ctx->ebml.doctype, &doctype) != 0) - doctype = "matroska"; - if (!!strcmp(doctype, "webm") && !!strcmp(doctype, "matroska")) { - nestegg_destroy(ctx); - return -1; - } - - if (ne_get_uint(ctx->ebml.doctype_read_version, &docversion) != 0) - docversion = 1; - if (docversion < 1 || docversion > 2) { - nestegg_destroy(ctx); - return -1; - } - - if (!ctx->segment.tracks.track_entry.head) { - nestegg_destroy(ctx); - return -1; - } - - track = ctx->segment.tracks.track_entry.head; - ctx->track_count = 0; - - while (track) { - ctx->track_count += 1; - track = track->next; - } - - r = ne_ctx_save(ctx, &ctx->saved); - if (r != 0) { - nestegg_destroy(ctx); - return -1; - } - - *context = ctx; - - return 0; -} - -void -nestegg_destroy(nestegg * ctx) -{ - assert(ctx->ancestor == NULL); - ne_pool_destroy(ctx->alloc_pool); - free(ctx->io); - free(ctx); -} - -int -nestegg_duration(nestegg * ctx, uint64_t * duration) -{ - uint64_t tc_scale; - double unscaled_duration; - - if (ne_get_float(ctx->segment.info.duration, &unscaled_duration) != 0) - return -1; - - tc_scale = ne_get_timecode_scale(ctx); - if (tc_scale == 0) - return -1; - - if (unscaled_duration != unscaled_duration || - unscaled_duration < 0 || unscaled_duration >= (double) UINT64_MAX || - (uint64_t) unscaled_duration > UINT64_MAX / tc_scale) - return -1; - - *duration = (uint64_t) (unscaled_duration * tc_scale); - return 0; -} - -int -nestegg_tstamp_scale(nestegg * ctx, uint64_t * scale) -{ - *scale = ne_get_timecode_scale(ctx); - if (*scale == 0) - return -1; - return 0; -} - -int -nestegg_track_count(nestegg * ctx, unsigned int * tracks) -{ - *tracks = ctx->track_count; - return 0; -} - -int -nestegg_get_cue_point(nestegg * ctx, unsigned int cluster_num, int64_t max_offset, - int64_t * start_pos, int64_t * end_pos, uint64_t * tstamp) -{ - int range_obtained = 0; - unsigned int cluster_count = 0; - struct cue_point * cue_point; - struct cue_track_positions * pos; - uint64_t seek_pos, track_number, tc_scale, time; - struct ebml_list_node * cues_node = ctx->segment.cues.cue_point.head; - struct ebml_list_node * cue_pos_node = NULL; - unsigned int track = 0, track_count = 0, track_index; - - if (!start_pos || !end_pos || !tstamp) - return -1; - - /* Initialise return values */ - *start_pos = -1; - *end_pos = -1; - *tstamp = 0; - - if (!cues_node) { - ne_init_cue_points(ctx, max_offset); - cues_node = ctx->segment.cues.cue_point.head; - /* Verify cues have been added to context. */ - if (!cues_node) - return -1; - } - - nestegg_track_count(ctx, &track_count); - - tc_scale = ne_get_timecode_scale(ctx); - if (tc_scale == 0) - return -1; - - while (cues_node && !range_obtained) { - assert(cues_node->id == ID_CUE_POINT); - cue_point = cues_node->data; - cue_pos_node = cue_point->cue_track_positions.head; - while (cue_pos_node) { - assert(cue_pos_node->id == ID_CUE_TRACK_POSITIONS); - pos = cue_pos_node->data; - for (track = 0; track < track_count; ++track) { - if (ne_get_uint(pos->track, &track_number) != 0) - return -1; - - if (ne_map_track_number_to_index(ctx, track_number, &track_index) != 0) - return -1; - - if (track_index == track) { - if (ne_get_uint(pos->cluster_position, &seek_pos) != 0) - return -1; - if (cluster_count == cluster_num) { - *start_pos = ctx->segment_offset + seek_pos; - if (ne_get_uint(cue_point->time, &time) != 0) - return -1; - *tstamp = time * tc_scale; - } else if (cluster_count == cluster_num + 1) { - *end_pos = ctx->segment_offset + seek_pos - 1; - range_obtained = 1; - break; - } - cluster_count++; - } - } - cue_pos_node = cue_pos_node->next; - } - cues_node = cues_node->next; - } - - return 0; -} - -int -nestegg_offset_seek(nestegg * ctx, uint64_t offset) -{ - int r; - - if (offset > INT64_MAX) - return -1; - - /* Seek and set up parser state for segment-level element (Cluster). */ - r = ne_io_seek(ctx->io, offset, NESTEGG_SEEK_SET); - if (r != 0) - return -1; - ctx->last_valid = 0; - - assert(ctx->ancestor == NULL); - - return 0; -} - -int -nestegg_track_seek(nestegg * ctx, unsigned int track, uint64_t tstamp) -{ - int r; - struct cue_point * cue_point; - struct cue_track_positions * pos; - uint64_t seek_pos, tc_scale; - - /* If there are no cues loaded, check for cues element in the seek head - and load it. */ - if (!ctx->segment.cues.cue_point.head) { - r = ne_init_cue_points(ctx, -1); - if (r != 0) - return -1; - } - - tc_scale = ne_get_timecode_scale(ctx); - if (tc_scale == 0) - return -1; - - cue_point = ne_find_cue_point_for_tstamp(ctx, ctx->segment.cues.cue_point.head, - track, tc_scale, tstamp); - if (!cue_point) - return -1; - - pos = ne_find_cue_position_for_track(ctx, cue_point->cue_track_positions.head, track); - if (pos == NULL) - return -1; - - if (ne_get_uint(pos->cluster_position, &seek_pos) != 0) - return -1; - - /* Seek to (we assume) the start of a Cluster element. */ - r = nestegg_offset_seek(ctx, ctx->segment_offset + seek_pos); - if (r != 0) - return -1; - - return 0; -} - -int -nestegg_track_type(nestegg * ctx, unsigned int track) -{ - struct track_entry * entry; - uint64_t type; - - entry = ne_find_track_entry(ctx, track); - if (!entry) - return -1; - - if (ne_get_uint(entry->type, &type) != 0) - return -1; - - if (type & TRACK_TYPE_VIDEO) - return NESTEGG_TRACK_VIDEO; - - if (type & TRACK_TYPE_AUDIO) - return NESTEGG_TRACK_AUDIO; - - return NESTEGG_TRACK_UNKNOWN; -} - -int -nestegg_track_codec_id(nestegg * ctx, unsigned int track) -{ - char * codec_id; - struct track_entry * entry; - - entry = ne_find_track_entry(ctx, track); - if (!entry) - return -1; - - if (ne_get_string(entry->codec_id, &codec_id) != 0) - return -1; - - if (strcmp(codec_id, TRACK_ID_VP8) == 0) - return NESTEGG_CODEC_VP8; - - if (strcmp(codec_id, TRACK_ID_VP9) == 0) - return NESTEGG_CODEC_VP9; - - if (strcmp(codec_id, TRACK_ID_AV1) == 0) - return NESTEGG_CODEC_AV1; - - if (strcmp(codec_id, TRACK_ID_VORBIS) == 0) - return NESTEGG_CODEC_VORBIS; - - if (strcmp(codec_id, TRACK_ID_OPUS) == 0) - return NESTEGG_CODEC_OPUS; - - if (strcmp(codec_id, TRACK_ID_AVC1) == 0) - return NESTEGG_CODEC_AVC1; - - if (strcmp(codec_id, TRACK_ID_AAC) == 0) - return NESTEGG_CODEC_AAC; - - return NESTEGG_CODEC_UNKNOWN; -} - -int -nestegg_track_codec_data_count(nestegg * ctx, unsigned int track, - unsigned int * count) -{ - struct track_entry * entry; - struct ebml_binary codec_private; - int codec_id; - unsigned char * p; - - *count = 0; - - entry = ne_find_track_entry(ctx, track); - if (!entry) - return -1; - - codec_id = nestegg_track_codec_id(ctx, track); - - if (codec_id == NESTEGG_CODEC_OPUS || - codec_id == NESTEGG_CODEC_AAC) { - *count = 1; - return 0; - } - - if (codec_id != NESTEGG_CODEC_VORBIS) - return -1; - - if (ne_get_binary(entry->codec_private, &codec_private) != 0) - return -1; - - if (codec_private.length < 1) - return -1; - - p = codec_private.data; - *count = *p + 1; - - if (*count > 3) - return -1; - - return 0; -} - -int -nestegg_track_codec_data(nestegg * ctx, unsigned int track, unsigned int item, - unsigned char ** data, size_t * length) -{ - struct track_entry * entry; - struct ebml_binary codec_private; - - *data = NULL; - *length = 0; - - entry = ne_find_track_entry(ctx, track); - if (!entry) - return -1; - - if (nestegg_track_codec_id(ctx, track) != NESTEGG_CODEC_VORBIS && - nestegg_track_codec_id(ctx, track) != NESTEGG_CODEC_OPUS && - nestegg_track_codec_id(ctx, track) != NESTEGG_CODEC_AVC1 && - nestegg_track_codec_id(ctx, track) != NESTEGG_CODEC_AAC) - return -1; - - if (ne_get_binary(entry->codec_private, &codec_private) != 0) - return -1; - - if (nestegg_track_codec_id(ctx, track) == NESTEGG_CODEC_VORBIS) { - uint64_t count; - uint64_t sizes[3]; - size_t total; - unsigned char * p; - unsigned int i; - int r; - - nestegg_io io; - struct io_buffer userdata; - userdata.buffer = codec_private.data; - userdata.length = codec_private.length; - userdata.offset = 0; - - io.read = ne_buffer_read; - io.seek = ne_buffer_seek; - io.tell = ne_buffer_tell; - io.userdata = &userdata; - - total = 0; - - r = ne_read_uint(&io, &count, 1); - if (r != 1) - return r; - total += 1; - count += 1; - - if (count > 3) - return -1; - r = ne_read_xiph_lacing(&io, codec_private.length, &total, count, sizes); - if (r != 1) - return r; - - if (item >= count) - return -1; - - p = codec_private.data + total; - for (i = 0; i < item; ++i) { - p += sizes[i]; - } - assert((size_t) (p - codec_private.data) <= codec_private.length && - codec_private.length - (p - codec_private.data) >= sizes[item]); - *data = p; - *length = sizes[item]; - } else { - if (item >= 1) - return -1; - - *data = codec_private.data; - *length = codec_private.length; - } - - return 0; -} - -int -nestegg_track_video_params(nestegg * ctx, unsigned int track, - nestegg_video_params * params) -{ - struct track_entry * entry; - uint64_t value; - - memset(params, 0, sizeof(*params)); - - entry = ne_find_track_entry(ctx, track); - if (!entry) - return -1; - - if (nestegg_track_type(ctx, track) != NESTEGG_TRACK_VIDEO) - return -1; - - value = 0; - ne_get_uint(entry->video.stereo_mode, &value); - if (value <= NESTEGG_VIDEO_STEREO_TOP_BOTTOM || - value == NESTEGG_VIDEO_STEREO_RIGHT_LEFT) - params->stereo_mode = value; - - value = 0; - ne_get_uint(entry->video.alpha_mode, &value); - params->alpha_mode = value; - - if (ne_get_uint(entry->video.pixel_width, &value) != 0) - return -1; - params->width = value; - - if (ne_get_uint(entry->video.pixel_height, &value) != 0) - return -1; - params->height = value; - - value = 0; - ne_get_uint(entry->video.pixel_crop_bottom, &value); - params->crop_bottom = value; - - value = 0; - ne_get_uint(entry->video.pixel_crop_top, &value); - params->crop_top = value; - - value = 0; - ne_get_uint(entry->video.pixel_crop_left, &value); - params->crop_left = value; - - value = 0; - ne_get_uint(entry->video.pixel_crop_right, &value); - params->crop_right = value; - - value = params->width; - ne_get_uint(entry->video.display_width, &value); - params->display_width = value; - - value = params->height; - ne_get_uint(entry->video.display_height, &value); - params->display_height = value; - - return 0; -} - -int -nestegg_track_audio_params(nestegg * ctx, unsigned int track, - nestegg_audio_params * params) -{ - struct track_entry * entry; - uint64_t value; - - memset(params, 0, sizeof(*params)); - - entry = ne_find_track_entry(ctx, track); - if (!entry) - return -1; - - if (nestegg_track_type(ctx, track) != NESTEGG_TRACK_AUDIO) - return -1; - - params->rate = 8000; - ne_get_float(entry->audio.sampling_frequency, ¶ms->rate); - - value = 1; - ne_get_uint(entry->audio.channels, &value); - params->channels = value; - - value = 16; - ne_get_uint(entry->audio.bit_depth, &value); - params->depth = value; - - value = 0; - ne_get_uint(entry->codec_delay, &value); - params->codec_delay = value; - - value = 0; - ne_get_uint(entry->seek_preroll, &value); - params->seek_preroll = value; - - return 0; -} - -int -nestegg_track_encoding(nestegg * ctx, unsigned int track) -{ - struct track_entry * entry; - struct content_encoding * encoding; - uint64_t encoding_value; - - entry = ne_find_track_entry(ctx, track); - if (!entry) { - ctx->log(ctx, NESTEGG_LOG_ERROR, "No track entry found"); - return -1; - } - - if (!entry->content_encodings.content_encoding.head) { - /* Default encoding is compression */ - return NESTEGG_ENCODING_COMPRESSION; - } - - encoding = entry->content_encodings.content_encoding.head->data; - - encoding_value = NESTEGG_ENCODING_COMPRESSION; - ne_get_uint(encoding->content_encoding_type, &encoding_value); - if (encoding_value != NESTEGG_ENCODING_COMPRESSION && encoding_value != NESTEGG_ENCODING_ENCRYPTION) { - ctx->log(ctx, NESTEGG_LOG_ERROR, "Invalid ContentEncoding element found"); - return -1; - } - - return encoding_value; -} - -int -nestegg_track_content_enc_key_id(nestegg * ctx, unsigned int track, unsigned char const ** content_enc_key_id, - size_t * content_enc_key_id_length) -{ - struct track_entry * entry; - struct content_encoding * encoding; - struct content_encryption * encryption; - struct content_enc_aes_settings * aes_settings; - struct nestegg_encryption_params; - uint64_t value; - struct ebml_binary enc_key_id; - - entry = ne_find_track_entry(ctx, track); - if (!entry) { - ctx->log(ctx, NESTEGG_LOG_ERROR, "No track entry found"); - return -1; - } - - if (!entry->content_encodings.content_encoding.head) { - ctx->log(ctx, NESTEGG_LOG_ERROR, "No ContentEncoding element found"); - return -1; - } - - encoding = entry->content_encodings.content_encoding.head->data; - - value = 0; - ne_get_uint(encoding->content_encoding_type, &value); - if (value != NESTEGG_ENCODING_ENCRYPTION) { - ctx->log(ctx, NESTEGG_LOG_ERROR, "Disallowed ContentEncodingType found"); - return -1; - } - - if (!encoding->content_encryption.head) { - ctx->log(ctx, NESTEGG_LOG_ERROR, "No ContentEncryption element found"); - return -1; - } - - encryption = encoding->content_encryption.head->data; - - value = 0; - ne_get_uint(encryption->content_enc_algo, &value); - - if (value != CONTENT_ENC_ALGO_AES) { - ctx->log(ctx, NESTEGG_LOG_ERROR, "Disallowed ContentEncAlgo found"); - return -1; - } - - if (!encryption->content_enc_aes_settings.head) { - ctx->log(ctx, NESTEGG_LOG_ERROR, "No ContentEncAesSettings element found"); - return -1; - } - - aes_settings = encryption->content_enc_aes_settings.head->data; - value = AES_SETTINGS_CIPHER_CTR; - ne_get_uint(aes_settings->aes_settings_cipher_mode, &value); - - if (value != AES_SETTINGS_CIPHER_CTR) { - ctx->log(ctx, NESTEGG_LOG_ERROR, "Disallowed AESSettingCipherMode used"); - return -1; - } - - if (ne_get_binary(encryption->content_enc_key_id, &enc_key_id) != 0) { - ctx->log(ctx, NESTEGG_LOG_ERROR, "Could not retrieve track ContentEncKeyId"); - return -1; - } - - *content_enc_key_id = enc_key_id.data; - *content_enc_key_id_length = enc_key_id.length; - - return 0; -} - -int -nestegg_track_default_duration(nestegg * ctx, unsigned int track, - uint64_t * duration) -{ - struct track_entry * entry; - uint64_t value; - - entry = ne_find_track_entry(ctx, track); - if (!entry) - return -1; - - if (ne_get_uint(entry->default_duration, &value) != 0) - return -1; - *duration = value; - - return 0; -} - -int -nestegg_read_reset(nestegg * ctx) -{ - assert(ctx->ancestor == NULL); - return ne_ctx_restore(ctx, &ctx->saved); -} - -int -nestegg_read_packet(nestegg * ctx, nestegg_packet ** pkt) -{ - int r, read_block = 0; - uint64_t id, size; - - *pkt = NULL; - - assert(ctx->ancestor == NULL); - - /* Prepare for read_reset to resume parsing from this point upon error. */ - r = ne_ctx_save(ctx, &ctx->saved); - if (r != 0) - return -1; - - while (!read_block) { - r = ne_read_element(ctx, &id, &size); - if (r != 1) - return r; - - switch (id) { - case ID_CLUSTER: { - r = ne_read_element(ctx, &id, &size); - if (r != 1) - return r; - - /* Some files have a crc32 element, since it also has to be first it - conflicts with the timecode spec. Just ignore it */ - if (id == ID_CRC32) { - ctx->log(ctx, NESTEGG_LOG_DEBUG, - "read_packet: skipping crc element in a cluster"); - r = ne_io_read_skip(ctx->io, size); - if (r != 1) - return r; - r = ne_read_element(ctx, &id, &size); - if (r != 1) - return r; - } - - /* Timecode must be the first element in a Cluster, per spec. */ - if (id != ID_TIMECODE) - return -1; - - r = ne_read_uint(ctx->io, &ctx->cluster_timecode, size); - if (r != 1) - return r; - ctx->read_cluster_timecode = 1; - break; - } - case ID_SIMPLE_BLOCK: - r = ne_read_block(ctx, id, size, pkt); - if (r != 1) - return r; - - read_block = 1; - break; - case ID_BLOCK_GROUP: { - int64_t block_group_end; - uint64_t block_duration = 0; - int read_block_duration = 0; - int64_t discard_padding = 0; - int read_discard_padding = 0; - int64_t reference_block = 0; - int read_reference_block = 0; - struct block_additional * block_additional = NULL; - uint64_t tc_scale; - - block_group_end = ne_io_tell(ctx->io) + size; - - /* Read the entire BlockGroup manually. */ - while (ne_io_tell(ctx->io) < block_group_end) { - r = ne_read_element(ctx, &id, &size); - if (r != 1) { - ne_free_block_additions(block_additional); - if (*pkt) { - nestegg_free_packet(*pkt); - *pkt = NULL; - } - return r; - } - - switch (id) { - case ID_BLOCK: { - if (*pkt) { - ctx->log(ctx, NESTEGG_LOG_DEBUG, - "read_packet: multiple Blocks in BlockGroup, dropping previously read Block"); - nestegg_free_packet(*pkt); - } - r = ne_read_block(ctx, id, size, pkt); - if (r != 1) { - ne_free_block_additions(block_additional); - if (*pkt) { - nestegg_free_packet(*pkt); - *pkt = NULL; - } - return r; - } - - read_block = 1; - break; - } - case ID_BLOCK_DURATION: { - r = ne_read_uint(ctx->io, &block_duration, size); - if (r != 1) { - ne_free_block_additions(block_additional); - if (*pkt) { - nestegg_free_packet(*pkt); - *pkt = NULL; - } - return r; - } - tc_scale = ne_get_timecode_scale(ctx); - if (tc_scale == 0) { - ne_free_block_additions(block_additional); - if (*pkt) { - nestegg_free_packet(*pkt); - *pkt = NULL; - } - return -1; - } - block_duration *= tc_scale; - read_block_duration = 1; - break; - } - case ID_DISCARD_PADDING: { - r = ne_read_int(ctx->io, &discard_padding, size); - if (r != 1) { - ne_free_block_additions(block_additional); - if (*pkt) { - nestegg_free_packet(*pkt); - *pkt = NULL; - } - return r; - } - read_discard_padding = 1; - break; - } - case ID_BLOCK_ADDITIONS: { - /* There should only be one BlockAdditions; treat multiple as an error. */ - if (block_additional) { - ne_free_block_additions(block_additional); - if (*pkt) { - nestegg_free_packet(*pkt); - *pkt = NULL; - } - return -1; - } - r = ne_read_block_additions(ctx, size, &block_additional); - if (r != 1) { - ne_free_block_additions(block_additional); - if (*pkt) { - nestegg_free_packet(*pkt); - *pkt = NULL; - } - return r; - } - break; - } - case ID_REFERENCE_BLOCK: { - r = ne_read_int(ctx->io, &reference_block, size); - if (r != 1) { - ne_free_block_additions(block_additional); - if (*pkt) { - nestegg_free_packet(*pkt); - *pkt = NULL; - } - return r; - } - read_reference_block = 1; - break; - } - default: - /* We don't know what this element is, so skip over it */ - if (id != ID_VOID && id != ID_CRC32) - ctx->log(ctx, NESTEGG_LOG_DEBUG, - "read_packet: unknown element %llx in BlockGroup", id); - r = ne_io_read_skip(ctx->io, size); - if (r != 1) { - ne_free_block_additions(block_additional); - if (*pkt) { - nestegg_free_packet(*pkt); - *pkt = NULL; - } - return r; - } - } - } - - assert(read_block == (*pkt != NULL)); - if (*pkt) { - (*pkt)->duration = block_duration; - (*pkt)->read_duration = read_block_duration; - (*pkt)->discard_padding = discard_padding; - (*pkt)->read_discard_padding = read_discard_padding; - (*pkt)->reference_block = reference_block; - (*pkt)->read_reference_block = read_reference_block; - (*pkt)->block_additional = block_additional; - if ((*pkt)->read_reference_block) - /* If a packet has a reference block it contains - predictive frames and no keyframes */ - (*pkt)->keyframe = NESTEGG_PACKET_HAS_KEYFRAME_FALSE; - } else { - ne_free_block_additions(block_additional); - } - break; - } - default: - ctx->log(ctx, NESTEGG_LOG_DEBUG, "read_packet: unknown element %llx", id); - r = ne_io_read_skip(ctx->io, size); - if (r != 1) - return r; - } - } - - return 1; -} - -void -nestegg_free_packet(nestegg_packet * pkt) -{ - struct frame * frame; - - while (pkt->frame) { - frame = pkt->frame; - pkt->frame = frame->next; - - ne_free_frame(frame); - } - - ne_free_block_additions(pkt->block_additional); - - free(pkt); -} - -int -nestegg_packet_has_keyframe(nestegg_packet * pkt) -{ - return pkt->keyframe; -} - -int -nestegg_packet_track(nestegg_packet * pkt, unsigned int * track) -{ - *track = pkt->track; - return 0; -} - -int -nestegg_packet_tstamp(nestegg_packet * pkt, uint64_t * tstamp) -{ - *tstamp = pkt->timecode; - return 0; -} - -int -nestegg_packet_duration(nestegg_packet * pkt, uint64_t * duration) -{ - if (!pkt->read_duration) - return -1; - *duration = pkt->duration; - return 0; -} - -int -nestegg_packet_discard_padding(nestegg_packet * pkt, int64_t * discard_padding) -{ - if (!pkt->read_discard_padding) - return -1; - *discard_padding = pkt->discard_padding; - return 0; -} - -int -nestegg_packet_reference_block(nestegg_packet * pkt, int64_t * reference_block) -{ - if (!pkt->read_reference_block) - return -1; - *reference_block = pkt->reference_block; - return 0; -} - -int -nestegg_packet_count(nestegg_packet * pkt, unsigned int * count) -{ - struct frame * f = pkt->frame; - - *count = 0; - - while (f) { - *count += 1; - f = f->next; - } - - return 0; -} - -int -nestegg_packet_data(nestegg_packet * pkt, unsigned int item, - unsigned char ** data, size_t * length) -{ - struct frame * f = pkt->frame; - unsigned int count = 0; - - *data = NULL; - *length = 0; - - while (f) { - if (count == item) { - *data = f->data; - *length = f->length; - return 0; - } - count += 1; - f = f->next; - } - - return -1; -} - -int -nestegg_packet_additional_data(nestegg_packet * pkt, unsigned int id, - unsigned char ** data, size_t * length) -{ - struct block_additional * a = pkt->block_additional; - - *data = NULL; - *length = 0; - - while (a) { - if (a->id == id) { - *data = a->data; - *length = a->length; - return 0; - } - a = a->next; - } - - return -1; -} - -int -nestegg_packet_encryption(nestegg_packet * pkt) -{ - struct frame * f = pkt->frame; - unsigned char encrypted_bit; - unsigned char partitioned_bit; - - if (!f->frame_encryption) - return NESTEGG_PACKET_HAS_SIGNAL_BYTE_FALSE; - - /* Should never have parsed blocks with both encryption and lacing */ - assert(f->next == NULL); - - encrypted_bit = f->frame_encryption->signal_byte & ENCRYPTED_BIT_MASK; - partitioned_bit = f->frame_encryption->signal_byte & PARTITIONED_BIT_MASK; - - if (encrypted_bit != PACKET_ENCRYPTED) - return NESTEGG_PACKET_HAS_SIGNAL_BYTE_UNENCRYPTED; - - if (partitioned_bit == PACKET_PARTITIONED) - return NESTEGG_PACKET_HAS_SIGNAL_BYTE_PARTITIONED; - - return NESTEGG_PACKET_HAS_SIGNAL_BYTE_ENCRYPTED; -} - -int -nestegg_packet_iv(nestegg_packet * pkt, unsigned char const ** iv, size_t * length) -{ - struct frame * f = pkt->frame; - unsigned char encrypted_bit; - - *iv = NULL; - *length = 0; - if (!f->frame_encryption) - return -1; - - /* Should never have parsed blocks with both encryption and lacing */ - assert(f->next == NULL); - - encrypted_bit = f->frame_encryption->signal_byte & ENCRYPTED_BIT_MASK; - - if (encrypted_bit != PACKET_ENCRYPTED) - return 0; - - *iv = f->frame_encryption->iv; - *length = f->frame_encryption->length; - return 0; -} - -int -nestegg_packet_offsets(nestegg_packet * pkt, - uint32_t const ** partition_offsets, - uint8_t * num_partitions) -{ - struct frame * f = pkt->frame; - unsigned char encrypted_bit; - unsigned char partitioned_bit; - - *partition_offsets = NULL; - *num_partitions = 0; - - if (!f->frame_encryption) - return -1; - - /* Should never have parsed blocks with both encryption and lacing */ - assert(f->next == NULL); - - encrypted_bit = f->frame_encryption->signal_byte & ENCRYPTED_BIT_MASK; - partitioned_bit = f->frame_encryption->signal_byte & PARTITIONED_BIT_MASK; - - if (encrypted_bit != PACKET_ENCRYPTED || partitioned_bit != PACKET_PARTITIONED) - return -1; - - *num_partitions = f->frame_encryption->num_partitions; - *partition_offsets = f->frame_encryption->partition_offsets; - return 0; -} - -int -nestegg_has_cues(nestegg * ctx) -{ - return ctx->segment.cues.cue_point.head || - ne_find_seek_for_id(ctx->segment.seek_head.head, ID_CUES); -} - -int -nestegg_sniff(unsigned char const * buffer, size_t length) -{ - nestegg_io io; - struct io_buffer userdata; - - userdata.buffer = buffer; - userdata.length = length; - userdata.offset = 0; - - io.read = ne_buffer_read; - io.seek = ne_buffer_seek; - io.tell = ne_buffer_tell; - io.userdata = &userdata; - return ne_match_webm(io, length); -} diff --git a/media/libnestegg/update.sh b/media/libnestegg/update.sh deleted file mode 100755 index 644408e09..000000000 --- a/media/libnestegg/update.sh +++ /dev/null @@ -1,22 +0,0 @@ -# Usage: sh update.sh <upstream_src_directory> -cp $1/include/nestegg/nestegg.h include -cp $1/src/nestegg.c src -cp $1/LICENSE . -cp $1/README.md . -cp $1/AUTHORS . -if [ -d $1/.git ]; then - rev=$(cd $1 && git rev-parse --verify HEAD) - dirty=$(cd $1 && git diff-index --name-only HEAD) -fi - -if [ -n "$rev" ]; then - version=$rev - if [ -n "$dirty" ]; then - version=$version-dirty - echo "WARNING: updating from a dirty git repository." - fi - sed -i "/The git commit ID used was/ s/[0-9a-f]\+\(-dirty\)\?\./$version./" README_MCP -else - echo "Remember to update README_MCP with the version details." -fi - |