mirror of
https://github.com/libretro/RetroArch.git
synced 2024-11-24 16:39:43 +00:00
Merge pull request #8132 from alphanu1/master
CRTSwitchRes Updates: Including Raspberry PI
This commit is contained in:
commit
3d092c8394
@ -116,7 +116,7 @@ static void win32_display_server_destroy(void *data)
|
||||
|
||||
if (win32_orig_width > 0 && win32_orig_height > 0)
|
||||
video_display_server_set_resolution(win32_orig_width, win32_orig_height,
|
||||
win32_orig_refresh, (float)win32_orig_refresh, crt_center );
|
||||
win32_orig_refresh, (float)win32_orig_refresh, crt_center, 0);
|
||||
|
||||
#ifdef HAS_TASKBAR_EXT
|
||||
if (g_taskbarList)
|
||||
@ -210,7 +210,7 @@ static bool win32_display_server_set_window_decorations(void *data, bool on)
|
||||
}
|
||||
|
||||
static bool win32_display_server_set_resolution(void *data,
|
||||
unsigned width, unsigned height, int int_hz, float hz, int center)
|
||||
unsigned width, unsigned height, int int_hz, float hz, int center, int monitor_index)
|
||||
{
|
||||
DEVMODE curDevmode;
|
||||
int iModeNum;
|
||||
|
@ -19,6 +19,10 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/extensions/Xrandr.h> // run pkg-config --static --libs xrandr
|
||||
#include <X11/extensions/randr.h>
|
||||
#include <X11/extensions/Xrender.h>
|
||||
|
||||
#include "../../config.h"
|
||||
|
||||
@ -35,11 +39,15 @@
|
||||
static unsigned orig_width = 0;
|
||||
static unsigned orig_height = 0;
|
||||
static char old_mode[250] = {0};
|
||||
static char orig_output[250] = {0};
|
||||
static char new_mode[250] = {0};
|
||||
static char xrandr[250] = {0};
|
||||
static char fbset[150] = {0};
|
||||
static char output[500] = {0};
|
||||
static char output4[500] = {0};
|
||||
static bool crt_en = false;
|
||||
static unsigned crtid = 20;
|
||||
static XRRModeInfo crt_rrmode;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@ -64,26 +72,23 @@ static void x11_display_server_destroy(void *data)
|
||||
|
||||
if (crt_en)
|
||||
{
|
||||
|
||||
|
||||
snprintf(output, sizeof(output),
|
||||
"xrandr -s %dx%d", orig_width, orig_height);
|
||||
"xrandr --newmode \"700x480_59.94\" 13.849698 700 742 801 867 480 490 496 533 interlace -hsync -vsync");
|
||||
system(output);
|
||||
snprintf(output, sizeof(output),
|
||||
"xrandr --addmode %s 700x480_59.94", orig_output);
|
||||
system(output);
|
||||
snprintf(output, sizeof(output),
|
||||
"xrandr --output %s --mode 700x480_59.94", orig_output);
|
||||
system(output);
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
snprintf(output, sizeof(output),
|
||||
"xrandr --delmode %s%d %s", "VGA", i, old_mode);
|
||||
system(output);
|
||||
snprintf(output, sizeof(output),
|
||||
"xrandr --delmode %s-%d %s", "VGA", i, old_mode);
|
||||
system(output);
|
||||
snprintf(output, sizeof(output),
|
||||
"xrandr --delmode %s %s",orig_output, old_mode);
|
||||
system(output);
|
||||
|
||||
snprintf(output, sizeof(output),
|
||||
"xrandr --delmode %s%d %s", "DVI", i, old_mode);
|
||||
system(output);
|
||||
snprintf(output, sizeof(output),
|
||||
"xrandr --delmode %s-%d %s", "DVI", i, old_mode);
|
||||
system(output);
|
||||
}
|
||||
|
||||
|
||||
snprintf(output, sizeof(output), "xrandr --rmmode %s", old_mode);
|
||||
system(output);
|
||||
@ -126,7 +131,7 @@ static bool x11_display_server_set_window_decorations(void *data, bool on)
|
||||
}
|
||||
|
||||
static bool x11_display_server_set_resolution(void *data,
|
||||
unsigned width, unsigned height, int int_hz, float hz, int center)
|
||||
unsigned width, unsigned height, int int_hz, float hz, int center, int monitor_index)
|
||||
{
|
||||
int i = 0;
|
||||
int hfp = 0;
|
||||
@ -144,6 +149,13 @@ static bool x11_display_server_set_resolution(void *data,
|
||||
float pixel_clock = 0;
|
||||
|
||||
crt_en = true;
|
||||
sprintf(old_mode,"%s", new_mode);
|
||||
Display* dsp = XOpenDisplay(NULL);
|
||||
Screen* scrn = DefaultScreenOfDisplay(dsp);
|
||||
XRRScreenResources *res;
|
||||
int screen = DefaultScreen ( dsp );
|
||||
Window window = RootWindow ( dsp, screen );
|
||||
|
||||
|
||||
/* set core refresh from hz */
|
||||
video_monitor_set_refresh_rate(hz);
|
||||
@ -235,59 +247,67 @@ static bool x11_display_server_set_resolution(void *data,
|
||||
|
||||
/* need to run loops for DVI0 - DVI-2 and VGA0 - VGA-2 outputs to
|
||||
* add and delete modes */
|
||||
for (i = 0; i < 3; i++)
|
||||
crt_rrmode.id = crtid;
|
||||
crt_rrmode.width = width;
|
||||
crt_rrmode.height = height;
|
||||
crt_rrmode.dotClock = pixel_clock;
|
||||
crt_rrmode.hSyncStart = hfp;
|
||||
crt_rrmode.hSyncEnd = hsp;
|
||||
crt_rrmode.hTotal = hmax;
|
||||
crt_rrmode.hSkew = 0;
|
||||
crt_rrmode.vSyncStart = vfp;
|
||||
crt_rrmode.vSyncEnd = vsp;
|
||||
crt_rrmode.vTotal = vmax;
|
||||
crt_rrmode.name = new_mode;
|
||||
crt_rrmode.nameLength = sizeof(new_mode);
|
||||
crt_rrmode.modeFlags = 0;
|
||||
|
||||
res = XRRGetScreenResources (dsp, window);
|
||||
|
||||
if (monitor_index == 0)
|
||||
{
|
||||
snprintf(output, sizeof(output), "xrandr --addmode %s%d %s", "DVI", i,
|
||||
new_mode);
|
||||
system(output);
|
||||
snprintf(output, sizeof(output), "xrandr --delmode %s%d %s", "DVI", i,
|
||||
old_mode);
|
||||
system(output);
|
||||
}
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
snprintf(output, sizeof(output), "xrandr --addmode %s-%d %s", "DVI", i,
|
||||
new_mode);
|
||||
system(output);
|
||||
snprintf(output, sizeof(output), "xrandr --delmode %s-%d %s", "DVI", i,
|
||||
old_mode);
|
||||
system(output);
|
||||
}
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
snprintf(output, sizeof(output), "xrandr --addmode %s%d %s", "VGA", i, new_mode);
|
||||
system(output);
|
||||
snprintf(output, sizeof(output), "xrandr --delmode %s%d %s", "VGA", i, old_mode);
|
||||
system(output);
|
||||
}
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
snprintf(output, sizeof(output), "xrandr --addmode %s-%d %s", "VGA", i, new_mode);
|
||||
system(output);
|
||||
snprintf(output, sizeof(output), "xrandr --delmode %s-%d %s", "VGA", i, old_mode);
|
||||
system(output);
|
||||
}
|
||||
|
||||
snprintf(output, sizeof(output), "xrandr -s %s", new_mode);
|
||||
system(output);
|
||||
|
||||
/* remove old mode */
|
||||
snprintf(output, sizeof(output), "xrandr --rmmode %s", old_mode);
|
||||
system(output);
|
||||
|
||||
/* needs xdotool installed. needed to recapture window. */
|
||||
system("xdotool windowactivate $(xdotool search --class RetroArch)");
|
||||
|
||||
/* variable for old mode */
|
||||
snprintf(old_mode, sizeof(old_mode), "%s", new_mode);
|
||||
|
||||
/* needs xdotool installed. needed to recapture window. */
|
||||
system("xdotool windowactivate $(xdotool search --class RetroArch)");
|
||||
/* Second run needed as some times it runs to fast to capture first time */
|
||||
for (int i = 0; i < res->noutput; i++)
|
||||
{
|
||||
|
||||
|
||||
XRROutputInfo *outputs = XRRGetOutputInfo (dsp, res, res->outputs[i]);
|
||||
|
||||
if (outputs->connection == RR_Connected)
|
||||
{
|
||||
|
||||
snprintf(output4, sizeof(output4),"xrandr --addmode %s %s",outputs->name ,new_mode);
|
||||
system(output4);
|
||||
snprintf(output4, sizeof(output4),"xrandr --output %s --mode %s", outputs->name, new_mode);
|
||||
system(output4);
|
||||
|
||||
snprintf(output4, sizeof(output4),"xrandr --delmode %s %s", outputs->name,old_mode);
|
||||
system(output4);
|
||||
snprintf(output4, sizeof(output4),"xrandr --rmmode %s", old_mode);
|
||||
system(output4);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
if (monitor_index > 0)
|
||||
{
|
||||
|
||||
XRROutputInfo *outputs = XRRGetOutputInfo (dsp, res, res->outputs[monitor_index]);
|
||||
if (outputs->connection == RR_Connected)
|
||||
{
|
||||
snprintf(orig_output, sizeof(orig_output),"%s", outputs->name);
|
||||
|
||||
snprintf(output4, sizeof(output4),"xrandr --addmode %s %s",outputs->name ,new_mode);
|
||||
system(output4);
|
||||
snprintf(output4, sizeof(output4),"xrandr --output %s --mode %s", outputs->name, new_mode);
|
||||
system(output4);
|
||||
|
||||
snprintf(output4, sizeof(output4),"xrandr --delmode %s %s", outputs->name, old_mode);
|
||||
system(output4);
|
||||
snprintf(output4, sizeof(output4),"xrandr --rmmode %s", old_mode);
|
||||
system(output4);
|
||||
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
32
gfx/include/userland/.gitignore
vendored
Normal file
32
gfx/include/userland/.gitignore
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
# Build directory
|
||||
build/
|
||||
|
||||
# Compiled Object files
|
||||
*.slo
|
||||
*.lo
|
||||
*.o
|
||||
|
||||
# Compiled Dynamic libraries
|
||||
*.so
|
||||
|
||||
# Compiled Static libraries
|
||||
*.lai
|
||||
*.la
|
||||
*.a
|
||||
|
||||
*.raw
|
||||
*.rgb
|
||||
*.bgr
|
||||
*.h264
|
||||
*.264
|
||||
*.yuyv
|
||||
*.uyvy
|
||||
*.yvyu
|
||||
*.vyuy
|
||||
*.i420
|
||||
*.yuv
|
||||
*.jpg
|
||||
*.avi
|
||||
*.pts
|
||||
*.ppm
|
||||
*.mkv
|
132
gfx/include/userland/CMakeLists.txt
Normal file
132
gfx/include/userland/CMakeLists.txt
Normal file
@ -0,0 +1,132 @@
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
|
||||
project(vmcs_host_apps)
|
||||
|
||||
SET(PROJECT_VER_MAJOR 1)
|
||||
SET(PROJECT_VER_MINOR 0)
|
||||
SET(PROJECT_VER_PATCH 0)
|
||||
SET(PROJECT_VER "${PROJECT_VER_MAJOR}.${PROJECT_VER_MINOR}.${PROJECT_VER_PATCH}")
|
||||
SET(PROJECT_APIVER "${PROJECT_VER}")
|
||||
|
||||
if(ARM64)
|
||||
set(BUILD_MMAL FALSE)
|
||||
set(BUILD_MMAL_APPS FALSE)
|
||||
else()
|
||||
set(BUILD_MMAL TRUE)
|
||||
set(BUILD_MMAL_APPS TRUE)
|
||||
endif()
|
||||
set(vmcs_root ${PROJECT_SOURCE_DIR})
|
||||
get_filename_component(VIDEOCORE_ROOT . ABSOLUTE)
|
||||
|
||||
set(VCOS_PTHREADS_BUILD_SHARED TRUE)
|
||||
|
||||
include(makefiles/cmake/global_settings.cmake)
|
||||
include(makefiles/cmake/arm-linux.cmake)
|
||||
include(makefiles/cmake/vmcs.cmake)
|
||||
|
||||
enable_language(ASM)
|
||||
|
||||
# Global include paths
|
||||
include_directories(host_applications/framework)
|
||||
include_directories(${PROJECT_SOURCE_DIR})
|
||||
include_directories(interface/vcos/pthreads)
|
||||
include_directories(interface/vmcs_host/linux)
|
||||
include_directories(interface/vmcs_host)
|
||||
include_directories(interface/vmcs_host/khronos)
|
||||
include_directories(interface/khronos/include)
|
||||
include_directories(${PROJECT_BINARY_DIR})
|
||||
include_directories(interface/vchiq_arm)
|
||||
#include_directories(tools/inet_transport)
|
||||
include_directories(host_support/include)
|
||||
|
||||
# Global compiler flags
|
||||
if(CMAKE_COMPILER_IS_GNUCC)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-multichar -Wall -Wno-unused-but-set-variable -fPIC")
|
||||
endif()
|
||||
|
||||
add_definitions(-D_REENTRANT)
|
||||
add_definitions(-DUSE_VCHIQ_ARM -DVCHI_BULK_ALIGN=1 -DVCHI_BULK_GRANULARITY=1)
|
||||
add_definitions(-DOMX_SKIP64BIT)
|
||||
add_definitions(-DEGL_SERVER_DISPMANX)
|
||||
add_definitions(-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64)
|
||||
add_definitions(-D_GNU_SOURCE)
|
||||
|
||||
# do we actually need this?
|
||||
add_definitions(-D__VIDEOCORE4__)
|
||||
add_definitions(-DTV_SUPPORTED_MODE_NO_DEPRECATED)
|
||||
|
||||
# add_definitions(-DKHRONOS_CLIENT_LOGGING)
|
||||
|
||||
# Check for OpenWF-C value set via command line
|
||||
if(KHRONOS_EGL_PLATFORM MATCHES "openwfc")
|
||||
add_definitions(-DKHRONOS_EGL_PLATFORM_OPENWFC)
|
||||
endif()
|
||||
|
||||
# List of subsidiary CMakeLists
|
||||
add_subdirectory(interface/vcos)
|
||||
add_subdirectory(interface/vmcs_host)
|
||||
add_subdirectory(interface/vchiq_arm)
|
||||
if(NOT ARM64)
|
||||
add_subdirectory(interface/khronos)
|
||||
endif()
|
||||
|
||||
#add_subdirectory(opensrc/tools/lua)
|
||||
if(BUILD_MMAL)
|
||||
include_directories(interface/mmal)
|
||||
add_subdirectory(interface/mmal)
|
||||
add_subdirectory(containers)
|
||||
endif()
|
||||
|
||||
# VidTex supports Android and Linux
|
||||
if(BUILD_MMAL_APPS)
|
||||
add_subdirectory(host_applications/android/apps/vidtex)
|
||||
endif(BUILD_MMAL_APPS)
|
||||
|
||||
if(NOT ARM64)
|
||||
add_subdirectory(middleware/openmaxil)
|
||||
endif()
|
||||
|
||||
# 3d demo code
|
||||
#if(NOT ANDROID)
|
||||
# add_subdirectory(thirdparty/applications/demos)
|
||||
# add_subdirectory(opensrc/applications/demos)
|
||||
#endif()
|
||||
|
||||
#if(ENABLE_3D_TESTS)
|
||||
# add_subdirectory(thirdparty/applications/test)
|
||||
#endif()
|
||||
|
||||
# FIXME: we should use a pre-packaged version of freetype
|
||||
# rather than the one included in the repo.
|
||||
#add_subdirectory(opensrc/helpers/freetype)
|
||||
#add_subdirectory(${PROJECT_SOURCE_DIR}/opensrc/helpers/fonts/ttf-bitstream-vera)
|
||||
|
||||
# VMCS Host Applications
|
||||
#add_subdirectory(host_applications/framework)
|
||||
|
||||
# add_subdirectory(interface/vchiq/test/win32)
|
||||
|
||||
# Apps and libraries supporting Camera Tuning Tool
|
||||
#add_subdirectory(tools/inet_transport/linux)
|
||||
#add_subdirectory(host_support/vcstandalone)
|
||||
|
||||
# add linux apps
|
||||
add_subdirectory(host_applications/linux)
|
||||
add_subdirectory(opensrc/helpers/libfdt)
|
||||
add_subdirectory(helpers/dtoverlay)
|
||||
|
||||
set(vmcs_host_apps_VERSION_MAJOR 1)
|
||||
set(vmcs_host_apps_VERSION_MINOR 0)
|
||||
|
||||
include_directories("${PROJECT_BINARY_DIR}")
|
||||
include(FindPkgConfig QUIET)
|
||||
if(PKG_CONFIG_FOUND)
|
||||
# Produce a pkg-config file
|
||||
foreach(PCFILE bcm_host.pc egl.pc glesv2.pc vg.pc brcmegl.pc brcmglesv2.pc brcmvg.pc vcsm.pc mmal.pc )
|
||||
configure_file("pkgconfig/${PCFILE}.in" "${PCFILE}" @ONLY)
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${PCFILE}"
|
||||
DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/pkgconfig")
|
||||
endforeach()
|
||||
endif()
|
||||
# Remove cache entry, if one added by command line
|
||||
unset(KHRONOS_EGL_PLATFORM CACHE)
|
26
gfx/include/userland/LICENCE
Normal file
26
gfx/include/userland/LICENCE
Normal file
@ -0,0 +1,26 @@
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
Copyright (c) 2015, Raspberry Pi (Trading) Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
8
gfx/include/userland/README.md
Normal file
8
gfx/include/userland/README.md
Normal file
@ -0,0 +1,8 @@
|
||||
This repository contains the source code for the ARM side libraries used on Raspberry Pi.
|
||||
These typically are installed in /opt/vc/lib and includes source for the ARM side code to interface to:
|
||||
EGL, mmal, GLESv2, vcos, openmaxil, vchiq_arm, bcm_host, WFC, OpenVG.
|
||||
|
||||
Use buildme to build. It requires cmake to be installed and an arm cross compiler. It is set up to use this one:
|
||||
https://github.com/raspberrypi/tools/tree/master/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian
|
||||
|
||||
Note that this repository does not contain the source for the edidparser and vcdbg binaries due to licensing restrictions.
|
44
gfx/include/userland/buildme
Normal file
44
gfx/include/userland/buildme
Normal file
@ -0,0 +1,44 @@
|
||||
#!/bin/bash
|
||||
BUILDTYPE=Release
|
||||
|
||||
if [ "$1" = "--debug" ]; then
|
||||
BUILDTYPE=Debug
|
||||
shift
|
||||
fi
|
||||
|
||||
BUILDSUBDIR=`echo $BUILDTYPE | tr '[A-Z]' '[a-z]'`;
|
||||
|
||||
if [ "armv6l" = `arch` ] || [ "armv7l" = `arch` ]; then
|
||||
# Native compile on the Raspberry Pi
|
||||
mkdir -p build/raspberry/$BUILDSUBDIR
|
||||
pushd build/raspberry/$BUILDSUBDIR
|
||||
cmake -DCMAKE_BUILD_TYPE=$BUILDTYPE ../../..
|
||||
if [ "armv6l" = `arch` ]; then
|
||||
make
|
||||
else
|
||||
make -j4
|
||||
fi
|
||||
if [ "$1" != "" ]; then
|
||||
sudo make install DESTDIR=$1
|
||||
else
|
||||
sudo make install
|
||||
fi
|
||||
elif [ "$1" = "--native" ]; then
|
||||
# Build natively on the host
|
||||
mkdir -p build/native/$BUILDSUBDIR
|
||||
pushd build/native/$BUILDSUBDIR
|
||||
cmake -DCMAKE_BUILD_TYPE=$BUILDTYPE ../../..
|
||||
shift
|
||||
make -j `nproc` $*
|
||||
else
|
||||
# Cross compile on a more capable machine
|
||||
mkdir -p build/arm-linux/$BUILDSUBDIR
|
||||
pushd build/arm-linux/$BUILDSUBDIR
|
||||
cmake -DCMAKE_TOOLCHAIN_FILE=../../../makefiles/cmake/toolchains/arm-linux-gnueabihf.cmake -DCMAKE_BUILD_TYPE=$BUILDTYPE ../../..
|
||||
make -j `nproc`
|
||||
|
||||
if [ "$1" != "" ]; then
|
||||
sudo make install DESTDIR=$1
|
||||
fi
|
||||
fi
|
||||
popd
|
124
gfx/include/userland/containers/CMakeLists.txt
Normal file
124
gfx/include/userland/containers/CMakeLists.txt
Normal file
@ -0,0 +1,124 @@
|
||||
SET( SOURCE_DIR . )
|
||||
|
||||
# We support building both static and shared libraries
|
||||
if (NOT DEFINED LIBRARY_TYPE)
|
||||
set(LIBRARY_TYPE SHARED)
|
||||
endif (NOT DEFINED LIBRARY_TYPE)
|
||||
|
||||
# Make sure the compiler can find the necessary include files
|
||||
include_directories (${SOURCE_DIR}/.. ${SOURCE_DIR}/../interface/vcos)
|
||||
|
||||
# Needed for the container loader
|
||||
add_definitions(-DDL_PATH_PREFIX="${VMCS_PLUGIN_DIR}/")
|
||||
|
||||
SET( GCC_COMPILER_FLAGS -Wall -g -O2 -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wcast-qual -Wwrite-strings -Wundef )
|
||||
SET( GCC_COMPILER_FLAGS ${GCC_COMPILER_FLAGS} -Wextra )#-Wno-missing-field-initializers )
|
||||
SET( GCC_COMPILER_FLAGS ${GCC_COMPILER_FLAGS} -std=c99 -D_POSIX_C_SOURCE=200112L )
|
||||
SET( GCC_COMPILER_FLAGS ${GCC_COMPILER_FLAGS} -Wno-missing-field-initializers )
|
||||
SET( GCC_COMPILER_FLAGS ${GCC_COMPILER_FLAGS} -Wno-unused-value )
|
||||
|
||||
add_definitions( ${GCC_COMPILER_FLAGS} )
|
||||
|
||||
# Containers core library
|
||||
set(core_SRCS ${core_SRCS} ${SOURCE_DIR}/core/containers.c)
|
||||
set(core_SRCS ${core_SRCS} ${SOURCE_DIR}/core/containers_io.c)
|
||||
set(core_SRCS ${core_SRCS} ${SOURCE_DIR}/core/containers_io_helpers.c)
|
||||
set(core_SRCS ${core_SRCS} ${SOURCE_DIR}/core/containers_codecs.c)
|
||||
set(core_SRCS ${core_SRCS} ${SOURCE_DIR}/core/containers_utils.c)
|
||||
set(core_SRCS ${core_SRCS} ${SOURCE_DIR}/core/containers_writer_utils.c)
|
||||
set(core_SRCS ${core_SRCS} ${SOURCE_DIR}/core/containers_loader.c)
|
||||
set(core_SRCS ${core_SRCS} ${SOURCE_DIR}/core/containers_filters.c)
|
||||
set(core_SRCS ${core_SRCS} ${SOURCE_DIR}/core/containers_logging.c)
|
||||
set(core_SRCS ${core_SRCS} ${SOURCE_DIR}/core/containers_uri.c)
|
||||
set(core_SRCS ${core_SRCS} ${SOURCE_DIR}/core/containers_bits.c)
|
||||
set(core_SRCS ${core_SRCS} ${SOURCE_DIR}/core/containers_list.c)
|
||||
set(core_SRCS ${core_SRCS} ${SOURCE_DIR}/core/containers_index.c)
|
||||
|
||||
# Containers io library
|
||||
set(io_SRCS ${io_SRCS} ${SOURCE_DIR}/io/io_file.c)
|
||||
set(io_SRCS ${io_SRCS} ${SOURCE_DIR}/io/io_null.c)
|
||||
set(io_SRCS ${io_SRCS} ${SOURCE_DIR}/io/io_net.c)
|
||||
set(io_SRCS ${io_SRCS} ${SOURCE_DIR}/io/io_pktfile.c)
|
||||
set(io_SRCS ${io_SRCS} ${SOURCE_DIR}/io/io_http.c)
|
||||
add_definitions( -DENABLE_CONTAINER_IO_HTTP )
|
||||
|
||||
# Containers net library
|
||||
if (DEFINED MSVC)
|
||||
set(net_SRCS ${net_SRCS} ${SOURCE_DIR}/net/net_sockets_common.c)
|
||||
set(net_SRCS ${net_SRCS} ${SOURCE_DIR}/net/net_sockets_win32.c)
|
||||
elseif (DEFINED LINUX OR DEFINED UNIX)
|
||||
set(net_SRCS ${net_SRCS} ${SOURCE_DIR}/net/net_sockets_common.c)
|
||||
set(net_SRCS ${net_SRCS} ${SOURCE_DIR}/net/net_sockets_bsd.c)
|
||||
else (DEFINED MSVC)
|
||||
set(net_SRCS ${net_SRCS} ${SOURCE_DIR}/net/net_sockets_null.c)
|
||||
endif (DEFINED MSVC)
|
||||
set(extra_net_SRCS net_sockets_win32.c net_sockets_win32.h net_sockets_null.c)
|
||||
add_custom_target(containers_net_extra ALL
|
||||
COMMAND touch ${extra_net_SRCS}
|
||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/containers/net)
|
||||
|
||||
# Packetizers library
|
||||
set(packetizers_SRCS ${packetizers_SRCS} ${SOURCE_DIR}/core/packetizers.c)
|
||||
set(packetizers_SRCS ${packetizers_SRCS} ${SOURCE_DIR}/mpga/mpga_packetizer.c)
|
||||
set(packetizers_SRCS ${packetizers_SRCS} ${SOURCE_DIR}/mpgv/mpgv_packetizer.c)
|
||||
set(packetizers_SRCS ${packetizers_SRCS} ${SOURCE_DIR}/pcm/pcm_packetizer.c)
|
||||
set(packetizers_SRCS ${packetizers_SRCS} ${SOURCE_DIR}/h264/avc1_packetizer.c)
|
||||
|
||||
add_library(containers ${LIBRARY_TYPE} ${core_SRCS} ${io_SRCS} ${net_SRCS} ${packetizers_SRCS})
|
||||
target_link_libraries(containers vcos)
|
||||
install(TARGETS containers DESTINATION lib)
|
||||
|
||||
set(container_readers)
|
||||
set(container_writers)
|
||||
|
||||
# Container modules
|
||||
add_subdirectory(mp4)
|
||||
set(container_readers ${container_readers} reader_mp4)
|
||||
set(container_writers ${container_writers} writer_mp4)
|
||||
add_subdirectory(mpeg)
|
||||
set(container_readers ${container_readers} reader_ps)
|
||||
add_subdirectory(mpga)
|
||||
set(container_readers ${container_readers} reader_mpga)
|
||||
add_subdirectory(binary)
|
||||
set(container_readers ${container_readers} reader_binary)
|
||||
set(container_writers ${container_writers} writer_binary)
|
||||
add_subdirectory(mkv)
|
||||
set(container_readers ${container_readers} reader_mkv)
|
||||
add_subdirectory(wav)
|
||||
set(container_readers ${container_readers} reader_wav)
|
||||
add_subdirectory(asf)
|
||||
set(container_readers ${container_readers} reader_asf)
|
||||
set(container_writers ${container_writers} writer_asf)
|
||||
add_subdirectory(flash)
|
||||
set(container_readers ${container_readers} reader_flv)
|
||||
add_subdirectory(avi)
|
||||
set(container_readers ${container_readers} reader_avi)
|
||||
set(container_writers ${container_writers} writer_avi)
|
||||
add_subdirectory(rtp)
|
||||
set(container_readers ${container_readers} reader_rtp)
|
||||
add_subdirectory(rtsp)
|
||||
set(container_readers ${container_readers} reader_rtsp)
|
||||
add_subdirectory(rcv)
|
||||
set(container_readers ${container_readers} reader_rcv)
|
||||
add_subdirectory(rv9)
|
||||
set(container_readers ${container_readers} reader_rv9)
|
||||
add_subdirectory(qsynth)
|
||||
set(container_readers ${container_readers} reader_qsynth)
|
||||
add_subdirectory(simple)
|
||||
set(container_readers ${container_readers} reader_simple)
|
||||
set(container_writers ${container_writers} writer_simple)
|
||||
add_subdirectory(raw)
|
||||
set(container_readers ${container_readers} reader_raw_video)
|
||||
set(container_writers ${container_writers} writer_raw_video)
|
||||
add_subdirectory(dummy)
|
||||
set(container_writers ${container_writers} writer_dummy)
|
||||
|
||||
add_subdirectory(metadata/id3)
|
||||
set(container_readers ${container_readers} reader_metadata_id3)
|
||||
|
||||
if (${LIBRARY_TYPE} STREQUAL STATIC)
|
||||
target_link_libraries(containers ${container_readers} ${container_writers})
|
||||
endif (${LIBRARY_TYPE} STREQUAL STATIC)
|
||||
|
||||
# Test apps
|
||||
add_subdirectory(test)
|
19
gfx/include/userland/containers/asf/CMakeLists.txt
Normal file
19
gfx/include/userland/containers/asf/CMakeLists.txt
Normal file
@ -0,0 +1,19 @@
|
||||
# Container module needs to go in as a plugins so different prefix
|
||||
# and install path
|
||||
set(CMAKE_SHARED_LIBRARY_PREFIX "")
|
||||
|
||||
# Make sure the compiler can find the necessary include files
|
||||
include_directories (../..)
|
||||
|
||||
add_library(reader_asf ${LIBRARY_TYPE} asf_reader.c)
|
||||
|
||||
target_link_libraries(reader_asf containers)
|
||||
|
||||
install(TARGETS reader_asf DESTINATION ${VMCS_PLUGIN_DIR})
|
||||
|
||||
add_library(writer_asf ${LIBRARY_TYPE} asf_writer.c)
|
||||
|
||||
target_link_libraries(writer_asf containers)
|
||||
|
||||
install(TARGETS writer_asf DESTINATION ${VMCS_PLUGIN_DIR})
|
||||
|
2247
gfx/include/userland/containers/asf/asf_reader.c
Normal file
2247
gfx/include/userland/containers/asf/asf_reader.c
Normal file
File diff suppressed because it is too large
Load Diff
577
gfx/include/userland/containers/asf/asf_writer.c
Normal file
577
gfx/include/userland/containers/asf/asf_writer.c
Normal file
@ -0,0 +1,577 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
//#define ENABLE_CONTAINERS_LOG_FORMAT
|
||||
#include "containers/core/containers_private.h"
|
||||
#include "containers/core/containers_io_helpers.h"
|
||||
#include "containers/core/containers_utils.h"
|
||||
#include "containers/core/containers_writer_utils.h"
|
||||
#include "containers/core/containers_logging.h"
|
||||
#undef CONTAINER_HELPER_LOG_INDENT
|
||||
#define CONTAINER_HELPER_LOG_INDENT(a) (a)->priv->module->object_level
|
||||
|
||||
VC_CONTAINER_STATUS_T asf_writer_open( VC_CONTAINER_T *p_ctx );
|
||||
|
||||
/******************************************************************************
|
||||
Defines.
|
||||
******************************************************************************/
|
||||
#define ASF_TRACKS_MAX 16
|
||||
#define ASF_OBJECT_HEADER_SIZE (16+8)
|
||||
|
||||
/******************************************************************************
|
||||
Type definitions.
|
||||
******************************************************************************/
|
||||
typedef enum {
|
||||
ASF_OBJECT_TYPE_UNKNOWN = 0,
|
||||
ASF_OBJECT_TYPE_HEADER,
|
||||
ASF_OBJECT_TYPE_FILE_PROPS,
|
||||
ASF_OBJECT_TYPE_STREAM_PROPS,
|
||||
ASF_OBJECT_TYPE_EXT_STREAM_PROPS,
|
||||
ASF_OBJECT_TYPE_DATA,
|
||||
ASF_OBJECT_TYPE_SIMPLE_INDEX,
|
||||
ASF_OBJECT_TYPE_INDEX,
|
||||
ASF_OBJECT_TYPE_HEADER_EXT,
|
||||
ASF_OBJECT_TYPE_HEADER_EXT_INTERNAL,
|
||||
ASF_OBJECT_TYPE_CODEC_LIST,
|
||||
ASF_OBJECT_TYPE_CONTENT_DESCRIPTION,
|
||||
ASF_OBJECT_TYPE_EXT_CONTENT_DESCRIPTION,
|
||||
ASF_OBJECT_TYPE_STREAM_BITRATE_PROPS,
|
||||
ASF_OBJECT_TYPE_LANGUAGE_LIST,
|
||||
ASF_OBJECT_TYPE_METADATA,
|
||||
ASF_OBJECT_TYPE_PADDING,
|
||||
} ASF_OBJECT_TYPE_T;
|
||||
|
||||
typedef struct VC_CONTAINER_TRACK_MODULE_T
|
||||
{
|
||||
unsigned int stream_id;
|
||||
uint64_t time_offset;
|
||||
bool b_valid;
|
||||
|
||||
uint64_t index_offset;
|
||||
uint32_t num_index_entries;
|
||||
int64_t index_time_interval;
|
||||
} VC_CONTAINER_TRACK_MODULE_T;
|
||||
|
||||
typedef struct VC_CONTAINER_MODULE_T
|
||||
{
|
||||
int object_level;
|
||||
uint32_t packet_size;
|
||||
|
||||
VC_CONTAINER_TRACK_T *tracks[ASF_TRACKS_MAX];
|
||||
|
||||
VC_CONTAINER_WRITER_EXTRAIO_T null;
|
||||
bool b_header_done;
|
||||
|
||||
unsigned int current_track;
|
||||
|
||||
} VC_CONTAINER_MODULE_T;
|
||||
|
||||
/******************************************************************************
|
||||
Static functions within this file.
|
||||
******************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T asf_write_object( VC_CONTAINER_T *p_ctx, ASF_OBJECT_TYPE_T object_type );
|
||||
static VC_CONTAINER_STATUS_T asf_write_object_header( VC_CONTAINER_T *p_ctx );
|
||||
static VC_CONTAINER_STATUS_T asf_write_object_header_ext( VC_CONTAINER_T *p_ctx );
|
||||
static VC_CONTAINER_STATUS_T asf_write_object_header_ext_internal( VC_CONTAINER_T *p_ctx );
|
||||
static VC_CONTAINER_STATUS_T asf_write_object_file_properties( VC_CONTAINER_T *p_ctx );
|
||||
static VC_CONTAINER_STATUS_T asf_write_object_stream_properties( VC_CONTAINER_T *p_ctx );
|
||||
static VC_CONTAINER_STATUS_T asf_write_object_ext_stream_properties( VC_CONTAINER_T *p_ctx );
|
||||
static VC_CONTAINER_STATUS_T asf_write_object_simple_index( VC_CONTAINER_T *p_ctx );
|
||||
static VC_CONTAINER_STATUS_T asf_write_object_index( VC_CONTAINER_T *p_ctx );
|
||||
static VC_CONTAINER_STATUS_T asf_write_object_data( VC_CONTAINER_T *p_ctx );
|
||||
#if 0
|
||||
static VC_CONTAINER_STATUS_T asf_write_object_codec_list( VC_CONTAINER_T *p_ctx );
|
||||
static VC_CONTAINER_STATUS_T asf_write_object_content_description( VC_CONTAINER_T *p_ctx );
|
||||
static VC_CONTAINER_STATUS_T asf_write_object_stream_bitrate_props( VC_CONTAINER_T *p_ctx );
|
||||
#endif
|
||||
|
||||
static const GUID_T asf_guid_header = {0x75B22630, 0x668E, 0x11CF, {0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C}};
|
||||
static const GUID_T asf_guid_file_props = {0x8CABDCA1, 0xA947, 0x11CF, {0x8E, 0xE4, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65}};
|
||||
static const GUID_T asf_guid_stream_props = {0xB7DC0791, 0xA9B7, 0x11CF, {0x8E, 0xE6, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65}};
|
||||
static const GUID_T asf_guid_ext_stream_props = {0x14E6A5CB, 0xC672, 0x4332, {0x83, 0x99, 0xA9, 0x69, 0x52, 0x06, 0x5B, 0x5A}};
|
||||
static const GUID_T asf_guid_data = {0x75B22636, 0x668E, 0x11CF, {0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C}};
|
||||
static const GUID_T asf_guid_simple_index = {0x33000890, 0xE5B1, 0x11CF, {0x89, 0xF4, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xCB}};
|
||||
static const GUID_T asf_guid_index = {0xD6E229D3, 0x35DA, 0x11D1, {0x90, 0x34, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xBE}};
|
||||
static const GUID_T asf_guid_header_ext = {0x5FBF03B5, 0xA92E, 0x11CF, {0x8E, 0xE3, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65}};
|
||||
static const GUID_T asf_guid_codec_list = {0x86D15240, 0x311D, 0x11D0, {0xA3, 0xA4, 0x00, 0xA0, 0xC9, 0x03, 0x48, 0xF6}};
|
||||
static const GUID_T asf_guid_content_description = {0x75B22633, 0x668E, 0x11CF, {0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C}};
|
||||
static const GUID_T asf_guid_ext_content_description = {0xD2D0A440, 0xE307, 0x11D2, {0x97, 0xF0, 0x00, 0xA0, 0xC9, 0x5E, 0xA8, 0x50}};
|
||||
static const GUID_T asf_guid_stream_bitrate_props = {0x7BF875CE, 0x468D, 0x11D1, {0x8D, 0x82, 0x00, 0x60, 0x97, 0xC9, 0xA2, 0xB2}};
|
||||
static const GUID_T asf_guid_language_list = {0x7C4346A9, 0xEFE0, 0x4BFC, {0xB2, 0x29, 0x39, 0x3E, 0xDE, 0x41, 0x5C, 0x85}};
|
||||
static const GUID_T asf_guid_metadata = {0xC5F8CBEA, 0x5BAF, 0x4877, {0x84, 0x67, 0xAA, 0x8C, 0x44, 0xFA, 0x4C, 0xCA}};
|
||||
static const GUID_T asf_guid_padding = {0x1806D474, 0xCADF, 0x4509, {0xA4, 0xBA, 0x9A, 0xAB, 0xCB, 0x96, 0xAA, 0xE8}};
|
||||
|
||||
static const GUID_T asf_guid_stream_type_video = {0xBC19EFC0, 0x5B4D, 0x11CF, {0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B}};
|
||||
static const GUID_T asf_guid_stream_type_audio = {0xF8699E40, 0x5B4D, 0x11CF, {0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B}};
|
||||
static const GUID_T asf_guid_error_correction = {0x20FB5700, 0x5B55, 0x11CF, {0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B}};
|
||||
|
||||
static struct {
|
||||
const ASF_OBJECT_TYPE_T type;
|
||||
const GUID_T *guid;
|
||||
const char *psz_name;
|
||||
VC_CONTAINER_STATUS_T (*pf_func)( VC_CONTAINER_T * );
|
||||
|
||||
} asf_object_list[] =
|
||||
{
|
||||
{ASF_OBJECT_TYPE_HEADER, &asf_guid_header, "header", asf_write_object_header},
|
||||
{ASF_OBJECT_TYPE_FILE_PROPS, &asf_guid_file_props, "file properties", asf_write_object_file_properties},
|
||||
{ASF_OBJECT_TYPE_STREAM_PROPS, &asf_guid_stream_props, "stream properties", asf_write_object_stream_properties},
|
||||
{ASF_OBJECT_TYPE_EXT_STREAM_PROPS, &asf_guid_ext_stream_props, "extended stream properties", asf_write_object_ext_stream_properties},
|
||||
{ASF_OBJECT_TYPE_DATA, &asf_guid_data, "data", asf_write_object_data},
|
||||
{ASF_OBJECT_TYPE_SIMPLE_INDEX, &asf_guid_simple_index, "simple index", asf_write_object_simple_index},
|
||||
{ASF_OBJECT_TYPE_INDEX, &asf_guid_index, "index", asf_write_object_index},
|
||||
{ASF_OBJECT_TYPE_HEADER_EXT, &asf_guid_header_ext, "header extension", asf_write_object_header_ext},
|
||||
{ASF_OBJECT_TYPE_HEADER_EXT_INTERNAL, &asf_guid_header_ext, "header extension", asf_write_object_header_ext_internal},
|
||||
#if 0
|
||||
{ASF_OBJECT_TYPE_CODEC_LIST, &asf_guid_codec_list, "codec list", asf_write_object_codec_list},
|
||||
{ASF_OBJECT_TYPE_CONTENT_DESCRIPTION, &asf_guid_content_description, "content description", asf_write_object_content_description},
|
||||
{ASF_OBJECT_TYPE_EXT_CONTENT_DESCRIPTION, &asf_guid_ext_content_description, "extended content description", 0},
|
||||
{ASF_OBJECT_TYPE_STREAM_BITRATE_PROPS, &asf_guid_stream_bitrate_props, "stream bitrate properties", asf_write_object_stream_bitrate_props},
|
||||
#endif
|
||||
{ASF_OBJECT_TYPE_UNKNOWN, 0, "unknown", 0}
|
||||
};
|
||||
|
||||
static GUID_T guid_null;
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T asf_write_object( VC_CONTAINER_T *p_ctx, ASF_OBJECT_TYPE_T type )
|
||||
{
|
||||
VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
|
||||
VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
|
||||
int64_t object_size = 0;
|
||||
unsigned int i;
|
||||
|
||||
/* Find out which object we want to write */
|
||||
for( i = 0; asf_object_list[i].type && asf_object_list[i].type != type; i++ );
|
||||
|
||||
/* Check we found the requested type */
|
||||
if(!asf_object_list[i].type)
|
||||
{
|
||||
vc_container_assert(0);
|
||||
return VC_CONTAINER_ERROR_CORRUPTED;
|
||||
}
|
||||
|
||||
/* We need to find out the size of the object we're going to write.
|
||||
* Because we want to be streamable, we can't just come back later to update the size field.
|
||||
* The easiest way to find out the size of the data we're going to write is to write a dummy
|
||||
* version of it and get the size from that. It is a bit wasteful but is so much easier and
|
||||
* shouldn't really impact performance as there's no actual i/o involved. */
|
||||
if(!vc_container_writer_extraio_enable(p_ctx, &module->null))
|
||||
{
|
||||
asf_object_list[i].pf_func(p_ctx);
|
||||
object_size = STREAM_POSITION(p_ctx);
|
||||
}
|
||||
vc_container_writer_extraio_disable(p_ctx, &module->null);
|
||||
|
||||
/* Special case for header extension internal function */
|
||||
if(type == ASF_OBJECT_TYPE_HEADER_EXT_INTERNAL)
|
||||
{
|
||||
WRITE_U32(p_ctx, object_size, "Header Extension Data Size");
|
||||
/* Call the object specific writing function */
|
||||
status = asf_object_list[i].pf_func(p_ctx);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Write the object header */
|
||||
|
||||
if(WRITE_GUID(p_ctx, asf_object_list[i].guid, "Object ID") != sizeof(GUID_T))
|
||||
return VC_CONTAINER_ERROR_EOS;
|
||||
|
||||
LOG_FORMAT(p_ctx, "Object Name: %s", asf_object_list[i].psz_name);
|
||||
|
||||
WRITE_U64(p_ctx, object_size + ASF_OBJECT_HEADER_SIZE, "Object Size");
|
||||
|
||||
module->object_level++;
|
||||
|
||||
/* Call the object specific writing function */
|
||||
status = asf_object_list[i].pf_func(p_ctx);
|
||||
|
||||
module->object_level--;
|
||||
|
||||
if(status != VC_CONTAINER_SUCCESS)
|
||||
LOG_DEBUG(p_ctx, "object %s appears to be corrupted", asf_object_list[i].psz_name);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static VC_CONTAINER_STATUS_T asf_write_object_header( VC_CONTAINER_T *p_ctx )
|
||||
{
|
||||
VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
|
||||
VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
|
||||
|
||||
WRITE_U32(p_ctx, 0, "Number of Header Objects"); /* FIXME: could use that */
|
||||
WRITE_U8(p_ctx, 0, "Reserved1");
|
||||
WRITE_U8(p_ctx, 0, "Reserved2");
|
||||
|
||||
status = asf_write_object(p_ctx, ASF_OBJECT_TYPE_FILE_PROPS);
|
||||
status = asf_write_object(p_ctx, ASF_OBJECT_TYPE_HEADER_EXT);
|
||||
|
||||
for(module->current_track = 0; module->current_track < p_ctx->tracks_num;
|
||||
module->current_track++)
|
||||
{
|
||||
status = asf_write_object(p_ctx, ASF_OBJECT_TYPE_STREAM_PROPS);
|
||||
}
|
||||
|
||||
/* Codec List */
|
||||
/* Content Description */
|
||||
/* Stream Bitrate Properties */
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static VC_CONTAINER_STATUS_T asf_write_object_header_ext( VC_CONTAINER_T *p_ctx )
|
||||
{
|
||||
WRITE_GUID(p_ctx, &guid_null, "Reserved Field 1");
|
||||
WRITE_U16(p_ctx, 0, "Reserved Field 2");
|
||||
|
||||
return asf_write_object(p_ctx, ASF_OBJECT_TYPE_HEADER_EXT_INTERNAL);
|
||||
}
|
||||
|
||||
static VC_CONTAINER_STATUS_T asf_write_object_header_ext_internal( VC_CONTAINER_T *p_ctx )
|
||||
{
|
||||
VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
|
||||
VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
|
||||
|
||||
for(module->current_track = 0; module->current_track < p_ctx->tracks_num;
|
||||
module->current_track++)
|
||||
{
|
||||
status = asf_write_object(p_ctx, ASF_OBJECT_TYPE_EXT_STREAM_PROPS);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static VC_CONTAINER_STATUS_T asf_write_object_file_properties( VC_CONTAINER_T *p_ctx )
|
||||
{
|
||||
VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
|
||||
|
||||
WRITE_GUID(p_ctx, &guid_null, "File ID");
|
||||
WRITE_U64(p_ctx, 0, "File Size");
|
||||
WRITE_U64(p_ctx, 0, "Creation Date");
|
||||
WRITE_U64(p_ctx, 0, "Data Packets Count");
|
||||
WRITE_U64(p_ctx, 0, "Play Duration");
|
||||
WRITE_U64(p_ctx, 0, "Send Duration");
|
||||
WRITE_U64(p_ctx, 0, "Preroll");
|
||||
WRITE_U32(p_ctx, 0, "Flags");
|
||||
WRITE_U32(p_ctx, module->packet_size, "Minimum Data Packet Size");
|
||||
WRITE_U32(p_ctx, module->packet_size, "Maximum Data Packet Size");
|
||||
WRITE_U32(p_ctx, 0, "Maximum Bitrate");
|
||||
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
static VC_CONTAINER_STATUS_T asf_write_bitmapinfoheader( VC_CONTAINER_T *p_ctx,
|
||||
VC_CONTAINER_TRACK_T *p_track )
|
||||
{
|
||||
uint32_t fourcc;
|
||||
|
||||
/* Write the preamble to the BITMAPINFOHEADER */
|
||||
WRITE_U32(p_ctx, p_track->format->type->video.width, "Encoded Image Width");
|
||||
WRITE_U32(p_ctx, p_track->format->type->video.height, "Encoded Image Height");
|
||||
WRITE_U8(p_ctx, 0, "Reserved Flags");
|
||||
WRITE_U16(p_ctx, 40 + p_track->format->extradata_size, "Format Data Size");
|
||||
|
||||
/* Write BITMAPINFOHEADER structure */
|
||||
WRITE_U32(p_ctx, 40 + p_track->format->extradata_size, "Format Data Size");
|
||||
WRITE_U32(p_ctx, p_track->format->type->video.width, "Image Width");
|
||||
WRITE_U32(p_ctx, p_track->format->type->video.height, "Image Height");
|
||||
WRITE_U16(p_ctx, 0, "Reserved");
|
||||
WRITE_U16(p_ctx, 0, "Bits Per Pixel Count");
|
||||
fourcc = codec_to_fourcc(p_track->format->codec);
|
||||
WRITE_BYTES(p_ctx, (char *)&fourcc, 4); /* Compression ID */
|
||||
LOG_FORMAT(p_ctx, "Compression ID: %4.4s", (char *)&fourcc);
|
||||
WRITE_U32(p_ctx, 0, "Image Size");
|
||||
WRITE_U32(p_ctx, 0, "Horizontal Pixels Per Meter");
|
||||
WRITE_U32(p_ctx, 0, "Vertical Pixels Per Meter");
|
||||
WRITE_U32(p_ctx, 0, "Colors Used Count");
|
||||
WRITE_U32(p_ctx, 0, "Important Colors Count");
|
||||
|
||||
WRITE_BYTES(p_ctx, p_track->format->extradata, p_track->format->extradata_size);
|
||||
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
static VC_CONTAINER_STATUS_T asf_write_waveformatex( VC_CONTAINER_T *p_ctx,
|
||||
VC_CONTAINER_TRACK_T *p_track)
|
||||
{
|
||||
/* Write WAVEFORMATEX structure */
|
||||
WRITE_U16(p_ctx, codec_to_waveformat(p_track->format->codec), "Codec ID");
|
||||
WRITE_U16(p_ctx, p_track->format->type->audio.channels, "Number of Channels");
|
||||
WRITE_U32(p_ctx, p_track->format->type->audio.sample_rate, "Samples per Second");
|
||||
WRITE_U32(p_ctx, p_track->format->bitrate, "Average Number of Bytes Per Second");
|
||||
WRITE_U16(p_ctx, p_track->format->type->audio.block_align, "Block Alignment");
|
||||
WRITE_U16(p_ctx, p_track->format->type->audio.bits_per_sample, "Bits Per Sample");
|
||||
WRITE_U16(p_ctx, p_track->format->extradata_size, "Codec Specific Data Size");
|
||||
WRITE_BYTES(p_ctx, p_track->format->extradata, p_track->format->extradata_size);
|
||||
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
static VC_CONTAINER_STATUS_T asf_write_object_stream_properties( VC_CONTAINER_T *p_ctx )
|
||||
{
|
||||
VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
|
||||
VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
|
||||
unsigned int track = module->current_track, ts_size = 0;
|
||||
const GUID_T *p_guid = &guid_null;
|
||||
|
||||
if(p_ctx->tracks[track]->format->es_type == VC_CONTAINER_ES_TYPE_VIDEO)
|
||||
{
|
||||
p_guid = &asf_guid_stream_type_video;
|
||||
ts_size = 11 + 40 + p_ctx->tracks[track]->format->extradata_size;
|
||||
}
|
||||
else if(p_ctx->tracks[track]->format->es_type == VC_CONTAINER_ES_TYPE_AUDIO)
|
||||
{
|
||||
p_guid = &asf_guid_stream_type_audio;
|
||||
ts_size = 18 + p_ctx->tracks[track]->format->extradata_size;
|
||||
}
|
||||
|
||||
WRITE_GUID(p_ctx, p_guid, "Stream Type");
|
||||
WRITE_GUID(p_ctx, &asf_guid_error_correction, "Error Correction Type");
|
||||
WRITE_U64(p_ctx, 0, "Time Offset");
|
||||
WRITE_U32(p_ctx, ts_size, "Type-Specific Data Length");
|
||||
WRITE_U32(p_ctx, 0, "Error Correction Data Length");
|
||||
WRITE_U16(p_ctx, track + 1, "Flags");
|
||||
WRITE_U32(p_ctx, 0, "Reserved");
|
||||
|
||||
/* Type-Specific Data */
|
||||
if(ts_size)
|
||||
{
|
||||
if(p_ctx->tracks[track]->format->es_type == VC_CONTAINER_ES_TYPE_VIDEO)
|
||||
status = asf_write_bitmapinfoheader( p_ctx, p_ctx->tracks[track]);
|
||||
else if(p_ctx->tracks[track]->format->es_type == VC_CONTAINER_ES_TYPE_AUDIO)
|
||||
status = asf_write_waveformatex( p_ctx, p_ctx->tracks[track]);
|
||||
}
|
||||
|
||||
/* Error Correction Data */
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static VC_CONTAINER_STATUS_T asf_write_object_ext_stream_properties( VC_CONTAINER_T *p_ctx )
|
||||
{
|
||||
VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
|
||||
|
||||
WRITE_U64(p_ctx, 0, "Start Time");
|
||||
WRITE_U64(p_ctx, 0, "End Time");
|
||||
WRITE_U32(p_ctx, 0, "Data Bitrate");
|
||||
WRITE_U32(p_ctx, 0, "Buffer Size");
|
||||
WRITE_U32(p_ctx, 0, "Initial Buffer Fullness");
|
||||
WRITE_U32(p_ctx, 0, "Alternate Data Bitrate");
|
||||
WRITE_U32(p_ctx, 0, "Alternate Buffer Size");
|
||||
WRITE_U32(p_ctx, 0, "Alternate Initial Buffer Fullness");
|
||||
WRITE_U32(p_ctx, 0, "Maximum Object Size");
|
||||
WRITE_U32(p_ctx, 0, "Flags");
|
||||
WRITE_U16(p_ctx, module->current_track + 1, "Stream Number");
|
||||
WRITE_U16(p_ctx, 0, "Stream Language ID Index");
|
||||
WRITE_U64(p_ctx, 0, "Average Time Per Frame");
|
||||
WRITE_U16(p_ctx, 0, "Stream Name Count");
|
||||
WRITE_U16(p_ctx, 0, "Payload Extension System Count");
|
||||
/* Stream Names */
|
||||
/* Payload Extension Systems */
|
||||
/* Stream Properties Object */
|
||||
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
static VC_CONTAINER_STATUS_T asf_write_object_index( VC_CONTAINER_T *p_ctx )
|
||||
{
|
||||
VC_CONTAINER_PARAM_UNUSED(p_ctx);
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
static VC_CONTAINER_STATUS_T asf_write_object_simple_index( VC_CONTAINER_T *p_ctx )
|
||||
{
|
||||
VC_CONTAINER_PARAM_UNUSED(p_ctx);
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
static VC_CONTAINER_STATUS_T asf_write_object_data( VC_CONTAINER_T *p_ctx )
|
||||
{
|
||||
VC_CONTAINER_PARAM_UNUSED(p_ctx);
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T asf_write_header( VC_CONTAINER_T *p_ctx )
|
||||
{
|
||||
VC_CONTAINER_STATUS_T status;
|
||||
|
||||
/* TODO Sanity check the tracks */
|
||||
|
||||
status = asf_write_object(p_ctx, ASF_OBJECT_TYPE_HEADER);
|
||||
status = asf_write_object(p_ctx, ASF_OBJECT_TYPE_DATA);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T asf_writer_write( VC_CONTAINER_T *p_ctx,
|
||||
VC_CONTAINER_PACKET_T *p_packet )
|
||||
{
|
||||
VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
|
||||
VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
|
||||
VC_CONTAINER_PARAM_UNUSED(p_packet);
|
||||
|
||||
if(!module->b_header_done)
|
||||
{
|
||||
module->b_header_done = true;
|
||||
status = asf_write_header(p_ctx);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T asf_writer_close( VC_CONTAINER_T *p_ctx )
|
||||
{
|
||||
VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
|
||||
|
||||
for(; p_ctx->tracks_num > 0; p_ctx->tracks_num--)
|
||||
vc_container_free_track(p_ctx, p_ctx->tracks[p_ctx->tracks_num-1]);
|
||||
|
||||
vc_container_writer_extraio_delete(p_ctx, &module->null);
|
||||
free(module);
|
||||
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T asf_writer_add_track( VC_CONTAINER_T *p_ctx, VC_CONTAINER_ES_FORMAT_T *format )
|
||||
{
|
||||
VC_CONTAINER_STATUS_T status;
|
||||
VC_CONTAINER_TRACK_T *track;
|
||||
|
||||
/* TODO check we support this format */
|
||||
|
||||
if(!(format->flags & VC_CONTAINER_ES_FORMAT_FLAG_FRAMED))
|
||||
return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
|
||||
|
||||
/* Allocate and initialise track data */
|
||||
if(p_ctx->tracks_num >= ASF_TRACKS_MAX) return VC_CONTAINER_ERROR_OUT_OF_RESOURCES;
|
||||
p_ctx->tracks[p_ctx->tracks_num] = track =
|
||||
vc_container_allocate_track(p_ctx, sizeof(*p_ctx->tracks[0]->priv->module));
|
||||
if(!track) return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
if(format->extradata_size)
|
||||
{
|
||||
status = vc_container_track_allocate_extradata( p_ctx, track, format->extradata_size );
|
||||
if(status) goto error;
|
||||
}
|
||||
|
||||
vc_container_format_copy(track->format, format, format->extradata_size);
|
||||
p_ctx->tracks_num++;
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
|
||||
error:
|
||||
vc_container_free_track(p_ctx, track);
|
||||
return status;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T asf_writer_control( VC_CONTAINER_T *p_ctx, VC_CONTAINER_CONTROL_T operation, va_list args )
|
||||
{
|
||||
VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
|
||||
VC_CONTAINER_STATUS_T status;
|
||||
|
||||
switch(operation)
|
||||
{
|
||||
case VC_CONTAINER_CONTROL_TRACK_ADD:
|
||||
{
|
||||
VC_CONTAINER_ES_FORMAT_T *p_format =
|
||||
(VC_CONTAINER_ES_FORMAT_T *)va_arg( args, VC_CONTAINER_ES_FORMAT_T * );
|
||||
return asf_writer_add_track(p_ctx, p_format);
|
||||
}
|
||||
|
||||
case VC_CONTAINER_CONTROL_TRACK_ADD_DONE:
|
||||
if(!module->b_header_done)
|
||||
{
|
||||
status = asf_write_header(p_ctx);
|
||||
if(status != VC_CONTAINER_SUCCESS) return status;
|
||||
module->b_header_done = true;
|
||||
}
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
|
||||
default: return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
Global function definitions.
|
||||
******************************************************************************/
|
||||
|
||||
VC_CONTAINER_STATUS_T asf_writer_open( VC_CONTAINER_T *p_ctx )
|
||||
{
|
||||
VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
const char *extension = vc_uri_path_extension(p_ctx->priv->uri);
|
||||
VC_CONTAINER_MODULE_T *module = 0;
|
||||
unsigned int i;
|
||||
|
||||
/* Check if the user has specified a container */
|
||||
vc_uri_find_query(p_ctx->priv->uri, 0, "container", &extension);
|
||||
|
||||
/* Check we're the right writer for this */
|
||||
if(!extension)
|
||||
return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
if(strcasecmp(extension, "asf") && strcasecmp(extension, "wmv") &&
|
||||
strcasecmp(extension, "wma"))
|
||||
return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
|
||||
/* Allocate our context */
|
||||
module = malloc(sizeof(*module));
|
||||
if(!module) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
|
||||
memset(module, 0, sizeof(*module));
|
||||
p_ctx->priv->module = module;
|
||||
p_ctx->tracks = module->tracks;
|
||||
|
||||
/* Create a null i/o writer to help us out in writing our data */
|
||||
status = vc_container_writer_extraio_create_null(p_ctx, &module->null);
|
||||
if(status != VC_CONTAINER_SUCCESS) goto error;
|
||||
|
||||
/* We'll only write the header once we've got all our tracks */
|
||||
|
||||
p_ctx->priv->pf_close = asf_writer_close;
|
||||
p_ctx->priv->pf_write = asf_writer_write;
|
||||
p_ctx->priv->pf_control = asf_writer_control;
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
|
||||
error:
|
||||
LOG_DEBUG(p_ctx, "asf: error opening stream");
|
||||
for(i = 0; i < ASF_TRACKS_MAX && p_ctx->tracks && p_ctx->tracks[i]; i++)
|
||||
vc_container_free_track(p_ctx, p_ctx->tracks[i]);
|
||||
free(module);
|
||||
return status;
|
||||
}
|
||||
|
||||
/********************************************************************************
|
||||
Entrypoint function
|
||||
********************************************************************************/
|
||||
|
||||
#if !defined(ENABLE_CONTAINERS_STANDALONE) && defined(__HIGHC__)
|
||||
# pragma weak writer_open asf_writer_open
|
||||
#endif
|
19
gfx/include/userland/containers/avi/CMakeLists.txt
Normal file
19
gfx/include/userland/containers/avi/CMakeLists.txt
Normal file
@ -0,0 +1,19 @@
|
||||
# Container module needs to go in as a plugins so different prefix
|
||||
# and install path
|
||||
set(CMAKE_SHARED_LIBRARY_PREFIX "")
|
||||
|
||||
# Make sure the compiler can find the necessary include files
|
||||
include_directories (../..)
|
||||
|
||||
add_library(reader_avi ${LIBRARY_TYPE} avi_reader.c)
|
||||
|
||||
target_link_libraries(reader_avi containers)
|
||||
|
||||
install(TARGETS reader_avi DESTINATION ${VMCS_PLUGIN_DIR})
|
||||
|
||||
add_library(writer_avi ${LIBRARY_TYPE} avi_writer.c)
|
||||
|
||||
target_link_libraries(writer_avi containers)
|
||||
|
||||
install(TARGETS writer_avi DESTINATION ${VMCS_PLUGIN_DIR})
|
||||
|
1521
gfx/include/userland/containers/avi/avi_reader.c
Normal file
1521
gfx/include/userland/containers/avi/avi_reader.c
Normal file
File diff suppressed because it is too large
Load Diff
1171
gfx/include/userland/containers/avi/avi_writer.c
Normal file
1171
gfx/include/userland/containers/avi/avi_writer.c
Normal file
File diff suppressed because it is too large
Load Diff
19
gfx/include/userland/containers/binary/CMakeLists.txt
Normal file
19
gfx/include/userland/containers/binary/CMakeLists.txt
Normal file
@ -0,0 +1,19 @@
|
||||
# Container module needs to go in as a plugins so different prefix
|
||||
# and install path
|
||||
set(CMAKE_SHARED_LIBRARY_PREFIX "")
|
||||
|
||||
# Make sure the compiler can find the necessary include files
|
||||
include_directories (../..)
|
||||
|
||||
add_library(reader_binary ${LIBRARY_TYPE} binary_reader.c)
|
||||
|
||||
target_link_libraries(reader_binary containers)
|
||||
|
||||
install(TARGETS reader_binary DESTINATION ${VMCS_PLUGIN_DIR})
|
||||
|
||||
add_library(writer_binary ${LIBRARY_TYPE} binary_writer.c)
|
||||
|
||||
target_link_libraries(writer_binary containers)
|
||||
|
||||
install(TARGETS writer_binary DESTINATION ${VMCS_PLUGIN_DIR})
|
||||
|
267
gfx/include/userland/containers/binary/binary_reader.c
Normal file
267
gfx/include/userland/containers/binary/binary_reader.c
Normal file
@ -0,0 +1,267 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "containers/core/containers_private.h"
|
||||
#include "containers/core/containers_io_helpers.h"
|
||||
#include "containers/core/containers_utils.h"
|
||||
#include "containers/core/containers_logging.h"
|
||||
|
||||
/******************************************************************************
|
||||
Defines.
|
||||
******************************************************************************/
|
||||
#define DEFAULT_BLOCK_SIZE (1024*16)
|
||||
/* Work-around for JPEG because our decoder expects that much at the start */
|
||||
#define DEFAULT_JPEG_BLOCK_SIZE (1024*80)
|
||||
|
||||
/******************************************************************************
|
||||
Type definitions
|
||||
******************************************************************************/
|
||||
typedef struct VC_CONTAINER_MODULE_T
|
||||
{
|
||||
VC_CONTAINER_TRACK_T *track;
|
||||
unsigned int default_block_size;
|
||||
unsigned int block_size;
|
||||
bool init;
|
||||
|
||||
VC_CONTAINER_STATUS_T status;
|
||||
|
||||
} VC_CONTAINER_MODULE_T;
|
||||
|
||||
static struct
|
||||
{
|
||||
const char *ext;
|
||||
VC_CONTAINER_ES_TYPE_T type;
|
||||
VC_CONTAINER_FOURCC_T codec;
|
||||
|
||||
} extension_to_format_table[] =
|
||||
{
|
||||
/* Audio */
|
||||
{"mp3", VC_CONTAINER_ES_TYPE_AUDIO, VC_CONTAINER_CODEC_MPGA},
|
||||
{"aac", VC_CONTAINER_ES_TYPE_AUDIO, VC_CONTAINER_CODEC_MP4A},
|
||||
{"adts", VC_CONTAINER_ES_TYPE_AUDIO, VC_CONTAINER_CODEC_MP4A},
|
||||
{"ac3", VC_CONTAINER_ES_TYPE_AUDIO, VC_CONTAINER_CODEC_AC3},
|
||||
{"ec3", VC_CONTAINER_ES_TYPE_AUDIO, VC_CONTAINER_CODEC_EAC3},
|
||||
{"amr", VC_CONTAINER_ES_TYPE_AUDIO, VC_CONTAINER_CODEC_AMRNB},
|
||||
{"awb", VC_CONTAINER_ES_TYPE_AUDIO, VC_CONTAINER_CODEC_AMRWB},
|
||||
{"evrc", VC_CONTAINER_ES_TYPE_AUDIO, VC_CONTAINER_CODEC_EVRC},
|
||||
{"dts", VC_CONTAINER_ES_TYPE_AUDIO, VC_CONTAINER_CODEC_DTS},
|
||||
|
||||
/* Video */
|
||||
{"m1v", VC_CONTAINER_ES_TYPE_VIDEO, VC_CONTAINER_CODEC_MP1V},
|
||||
{"m2v", VC_CONTAINER_ES_TYPE_VIDEO, VC_CONTAINER_CODEC_MP2V},
|
||||
{"m4v", VC_CONTAINER_ES_TYPE_VIDEO, VC_CONTAINER_CODEC_MP4V},
|
||||
{"mp4v", VC_CONTAINER_ES_TYPE_VIDEO, VC_CONTAINER_CODEC_MP4V},
|
||||
{"h263", VC_CONTAINER_ES_TYPE_VIDEO, VC_CONTAINER_CODEC_H263},
|
||||
{"263", VC_CONTAINER_ES_TYPE_VIDEO, VC_CONTAINER_CODEC_H263},
|
||||
{"h264", VC_CONTAINER_ES_TYPE_VIDEO, VC_CONTAINER_CODEC_H264},
|
||||
{"264", VC_CONTAINER_ES_TYPE_VIDEO, VC_CONTAINER_CODEC_H264},
|
||||
{"mvc", VC_CONTAINER_ES_TYPE_VIDEO, VC_CONTAINER_CODEC_MVC},
|
||||
{"vc1l", VC_CONTAINER_ES_TYPE_VIDEO, VC_CONTAINER_CODEC_WVC1},
|
||||
|
||||
/* Image */
|
||||
{"gif", VC_CONTAINER_ES_TYPE_VIDEO, VC_CONTAINER_CODEC_GIF},
|
||||
{"jpg", VC_CONTAINER_ES_TYPE_VIDEO, VC_CONTAINER_CODEC_JPEG},
|
||||
{"jpeg", VC_CONTAINER_ES_TYPE_VIDEO, VC_CONTAINER_CODEC_JPEG},
|
||||
{"png", VC_CONTAINER_ES_TYPE_VIDEO, VC_CONTAINER_CODEC_PNG},
|
||||
{"ppm", VC_CONTAINER_ES_TYPE_VIDEO, VC_CONTAINER_CODEC_PPM},
|
||||
{"tga", VC_CONTAINER_ES_TYPE_VIDEO, VC_CONTAINER_CODEC_TGA},
|
||||
{"bmp", VC_CONTAINER_ES_TYPE_VIDEO, VC_CONTAINER_CODEC_BMP},
|
||||
|
||||
{"bin", 0, 0},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
static struct
|
||||
{
|
||||
const char *ext;
|
||||
VC_CONTAINER_ES_TYPE_T type;
|
||||
VC_CONTAINER_FOURCC_T codec;
|
||||
|
||||
} bin_extension_to_format_table[] =
|
||||
{
|
||||
{"m4v.bin", VC_CONTAINER_ES_TYPE_VIDEO, VC_CONTAINER_CODEC_MP4V},
|
||||
{"263.bin", VC_CONTAINER_ES_TYPE_VIDEO, VC_CONTAINER_CODEC_H263},
|
||||
{"264.bin", VC_CONTAINER_ES_TYPE_VIDEO, VC_CONTAINER_CODEC_H264},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
Function prototypes
|
||||
******************************************************************************/
|
||||
VC_CONTAINER_STATUS_T binary_reader_open( VC_CONTAINER_T * );
|
||||
|
||||
/******************************************************************************
|
||||
Local Functions
|
||||
******************************************************************************/
|
||||
|
||||
/*****************************************************************************
|
||||
Functions exported as part of the Container Module API
|
||||
*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T binary_reader_read( VC_CONTAINER_T *p_ctx,
|
||||
VC_CONTAINER_PACKET_T *packet, uint32_t flags )
|
||||
{
|
||||
VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
|
||||
unsigned int size;
|
||||
|
||||
if(module->status != VC_CONTAINER_SUCCESS)
|
||||
return module->status;
|
||||
|
||||
if(!module->block_size)
|
||||
{
|
||||
module->block_size = module->default_block_size;
|
||||
module->init = 0;
|
||||
}
|
||||
|
||||
packet->size = module->block_size;
|
||||
packet->dts = packet->pts = VC_CONTAINER_TIME_UNKNOWN;
|
||||
if(module->init) packet->dts = packet->pts = 0;
|
||||
packet->track = 0;
|
||||
packet->flags = 0;
|
||||
|
||||
if(flags & VC_CONTAINER_READ_FLAG_SKIP)
|
||||
{
|
||||
size = SKIP_BYTES(p_ctx, module->block_size);
|
||||
module->block_size -= size;
|
||||
module->status = STREAM_STATUS(p_ctx);
|
||||
return module->status;
|
||||
}
|
||||
|
||||
if(flags & VC_CONTAINER_READ_FLAG_INFO)
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
|
||||
size = MIN(module->block_size, packet->buffer_size);
|
||||
size = READ_BYTES(p_ctx, packet->data, size);
|
||||
module->block_size -= size;
|
||||
packet->size = size;
|
||||
|
||||
module->status = size ? VC_CONTAINER_SUCCESS : STREAM_STATUS(p_ctx);
|
||||
return module->status;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T binary_reader_seek( VC_CONTAINER_T *p_ctx, int64_t *offset,
|
||||
VC_CONTAINER_SEEK_MODE_T mode, VC_CONTAINER_SEEK_FLAGS_T flags)
|
||||
{
|
||||
VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
|
||||
VC_CONTAINER_PARAM_UNUSED(module);
|
||||
VC_CONTAINER_PARAM_UNUSED(offset);
|
||||
VC_CONTAINER_PARAM_UNUSED(mode);
|
||||
VC_CONTAINER_PARAM_UNUSED(flags);
|
||||
return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T binary_reader_close( VC_CONTAINER_T *p_ctx )
|
||||
{
|
||||
VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
|
||||
for(; p_ctx->tracks_num > 0; p_ctx->tracks_num--)
|
||||
vc_container_free_track(p_ctx, p_ctx->tracks[p_ctx->tracks_num-1]);
|
||||
free(module);
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_CONTAINER_STATUS_T binary_reader_open( VC_CONTAINER_T *p_ctx )
|
||||
{
|
||||
const char *extension = vc_uri_path_extension(p_ctx->priv->uri);
|
||||
VC_CONTAINER_MODULE_T *module = 0;
|
||||
VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_FORMAT_INVALID;
|
||||
VC_CONTAINER_ES_TYPE_T es_type = 0;
|
||||
VC_CONTAINER_FOURCC_T codec = 0;
|
||||
unsigned int i;
|
||||
|
||||
/* Check if the user has specified a container */
|
||||
vc_uri_find_query(p_ctx->priv->uri, 0, "container", &extension);
|
||||
|
||||
/* Check if the extension is supported */
|
||||
if(!extension || !vc_uri_path(p_ctx->priv->uri))
|
||||
return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
for(i = 0; extension_to_format_table[i].ext; i++)
|
||||
{
|
||||
if(strcasecmp(extension, extension_to_format_table[i].ext))
|
||||
continue;
|
||||
|
||||
es_type = extension_to_format_table[i].type;
|
||||
codec = extension_to_format_table[i].codec;
|
||||
break;
|
||||
}
|
||||
if(!extension_to_format_table[i].ext) return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
|
||||
/* If this a .bin file we look in our bin list */
|
||||
for(i = 0; !codec && bin_extension_to_format_table[i].ext; i++)
|
||||
{
|
||||
if(!strstr(vc_uri_path(p_ctx->priv->uri), bin_extension_to_format_table[i].ext) &&
|
||||
!strstr(extension, bin_extension_to_format_table[i].ext))
|
||||
continue;
|
||||
|
||||
es_type = bin_extension_to_format_table[i].type;
|
||||
codec = bin_extension_to_format_table[i].codec;
|
||||
break;
|
||||
}
|
||||
if(!codec) return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
|
||||
/* Allocate our context */
|
||||
module = malloc(sizeof(*module));
|
||||
if(!module) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
|
||||
memset(module, 0, sizeof(*module));
|
||||
p_ctx->priv->module = module;
|
||||
p_ctx->tracks_num = 1;
|
||||
p_ctx->tracks = &module->track;
|
||||
p_ctx->tracks[0] = vc_container_allocate_track(p_ctx, 0);
|
||||
if(!p_ctx->tracks[0]) return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
|
||||
p_ctx->tracks[0]->format->es_type = es_type;
|
||||
p_ctx->tracks[0]->format->codec = codec;
|
||||
p_ctx->tracks[0]->is_enabled = true;
|
||||
module->default_block_size = DEFAULT_BLOCK_SIZE;
|
||||
if(codec == VC_CONTAINER_CODEC_JPEG)
|
||||
module->default_block_size = DEFAULT_JPEG_BLOCK_SIZE;
|
||||
module->block_size = module->default_block_size;
|
||||
module->init = 1;
|
||||
|
||||
/*
|
||||
* We now have all the information we really need to start playing the stream
|
||||
*/
|
||||
|
||||
p_ctx->priv->pf_close = binary_reader_close;
|
||||
p_ctx->priv->pf_read = binary_reader_read;
|
||||
p_ctx->priv->pf_seek = binary_reader_seek;
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
|
||||
error:
|
||||
LOG_DEBUG(p_ctx, "binary: error opening stream (%i)", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
/********************************************************************************
|
||||
Entrypoint function
|
||||
********************************************************************************/
|
||||
|
||||
#if !defined(ENABLE_CONTAINERS_STANDALONE) && defined(__HIGHC__)
|
||||
# pragma weak reader_open binary_reader_open
|
||||
#endif
|
160
gfx/include/userland/containers/binary/binary_writer.c
Normal file
160
gfx/include/userland/containers/binary/binary_writer.c
Normal file
@ -0,0 +1,160 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "containers/core/containers_private.h"
|
||||
#include "containers/core/containers_io_helpers.h"
|
||||
#include "containers/core/containers_utils.h"
|
||||
#include "containers/core/containers_logging.h"
|
||||
|
||||
/******************************************************************************
|
||||
Supported extensions
|
||||
******************************************************************************/
|
||||
static const char *extensions[] =
|
||||
{ "mp3", "aac", "adts", "ac3", "ec3", "amr", "awb", "evrc", "dts",
|
||||
"m1v", "m2v", "mp4v", "h263", "263", "h264", "264", "mvc",
|
||||
"bin", 0
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
Type definitions
|
||||
******************************************************************************/
|
||||
typedef struct VC_CONTAINER_MODULE_T
|
||||
{
|
||||
VC_CONTAINER_TRACK_T *track;
|
||||
|
||||
} VC_CONTAINER_MODULE_T;
|
||||
|
||||
/******************************************************************************
|
||||
Function prototypes
|
||||
******************************************************************************/
|
||||
VC_CONTAINER_STATUS_T binary_writer_open( VC_CONTAINER_T * );
|
||||
|
||||
/*****************************************************************************
|
||||
Functions exported as part of the Container Module API
|
||||
*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T binary_writer_close( VC_CONTAINER_T *p_ctx )
|
||||
{
|
||||
VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
|
||||
for(; p_ctx->tracks_num > 0; p_ctx->tracks_num--)
|
||||
vc_container_free_track(p_ctx, p_ctx->tracks[p_ctx->tracks_num-1]);
|
||||
free(module);
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T binary_writer_write( VC_CONTAINER_T *p_ctx,
|
||||
VC_CONTAINER_PACKET_T *packet )
|
||||
{
|
||||
WRITE_BYTES(p_ctx, packet->data, packet->size);
|
||||
return STREAM_STATUS(p_ctx);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T binary_writer_control( VC_CONTAINER_T *p_ctx,
|
||||
VC_CONTAINER_CONTROL_T operation, va_list args )
|
||||
{
|
||||
VC_CONTAINER_ES_FORMAT_T *format;
|
||||
VC_CONTAINER_TRACK_T *track;
|
||||
VC_CONTAINER_STATUS_T status;
|
||||
|
||||
switch(operation)
|
||||
{
|
||||
case VC_CONTAINER_CONTROL_TRACK_ADD:
|
||||
format = (VC_CONTAINER_ES_FORMAT_T *)va_arg( args, VC_CONTAINER_ES_FORMAT_T * );
|
||||
|
||||
/* Allocate and initialise track data */
|
||||
if(p_ctx->tracks_num >= 1) return VC_CONTAINER_ERROR_OUT_OF_RESOURCES;
|
||||
p_ctx->tracks[p_ctx->tracks_num] = track = vc_container_allocate_track(p_ctx, 0);
|
||||
if(!track) return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
if(format->extradata_size)
|
||||
{
|
||||
status = vc_container_track_allocate_extradata( p_ctx, track, format->extradata_size );
|
||||
if(status != VC_CONTAINER_SUCCESS)
|
||||
{
|
||||
vc_container_free_track(p_ctx, track);
|
||||
return status;
|
||||
}
|
||||
WRITE_BYTES(p_ctx, format->extradata, format->extradata_size);
|
||||
}
|
||||
|
||||
vc_container_format_copy(track->format, format, format->extradata_size);
|
||||
p_ctx->tracks_num++;
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
|
||||
case VC_CONTAINER_CONTROL_TRACK_ADD_DONE:
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
|
||||
default: return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_CONTAINER_STATUS_T binary_writer_open( VC_CONTAINER_T *p_ctx )
|
||||
{
|
||||
const char *extension = vc_uri_path_extension(p_ctx->priv->uri);
|
||||
VC_CONTAINER_MODULE_T *module = 0;
|
||||
VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_FORMAT_INVALID;
|
||||
unsigned int i;
|
||||
|
||||
/* Check if the user has specified a container */
|
||||
vc_uri_find_query(p_ctx->priv->uri, 0, "container", &extension);
|
||||
|
||||
/* Check we're the right writer for this */
|
||||
if(!extension)
|
||||
return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
for(i = 0; extensions[i]; i++)
|
||||
if(!strcasecmp(extension, extensions[i])) break;
|
||||
if(!extensions[i])
|
||||
return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
|
||||
/* Allocate our context */
|
||||
module = malloc(sizeof(*module));
|
||||
if(!module) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
|
||||
memset(module, 0, sizeof(*module));
|
||||
p_ctx->priv->module = module;
|
||||
p_ctx->tracks = &module->track;
|
||||
|
||||
p_ctx->priv->pf_close = binary_writer_close;
|
||||
p_ctx->priv->pf_write = binary_writer_write;
|
||||
p_ctx->priv->pf_control = binary_writer_control;
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
|
||||
error:
|
||||
LOG_DEBUG(p_ctx, "binary: error opening stream (%i)", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
/********************************************************************************
|
||||
Entrypoint function
|
||||
********************************************************************************/
|
||||
|
||||
#if !defined(ENABLE_CONTAINERS_STANDALONE) && defined(__HIGHC__)
|
||||
# pragma weak writer_open binary_writer_open
|
||||
#endif
|
746
gfx/include/userland/containers/containers.h
Normal file
746
gfx/include/userland/containers/containers.h
Normal file
@ -0,0 +1,746 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef VC_CONTAINERS_H
|
||||
#define VC_CONTAINERS_H
|
||||
|
||||
/** \file containers.h
|
||||
* Public API for container readers and writers
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "containers/containers_types.h"
|
||||
|
||||
/** \defgroup VcContainerApi Container API
|
||||
* API for container readers and writers */
|
||||
/* @{ */
|
||||
|
||||
/** Status codes returned by the container API */
|
||||
typedef enum
|
||||
{
|
||||
VC_CONTAINER_SUCCESS = 0, /**< No error */
|
||||
VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED, /**< Format of container is not supported */
|
||||
VC_CONTAINER_ERROR_FORMAT_FEATURE_NOT_SUPPORTED, /**< Format of container uses unsupported features */
|
||||
VC_CONTAINER_ERROR_FORMAT_INVALID, /**< Format of container is invalid */
|
||||
VC_CONTAINER_ERROR_CORRUPTED, /**< Container is corrupted */
|
||||
VC_CONTAINER_ERROR_URI_NOT_FOUND, /**< URI could not be found */
|
||||
VC_CONTAINER_ERROR_URI_OPEN_FAILED, /**< URI could not be opened */
|
||||
VC_CONTAINER_ERROR_OUT_OF_MEMORY, /**< Out of memory */
|
||||
VC_CONTAINER_ERROR_OUT_OF_SPACE, /**< Out of disk space (used when writing) */
|
||||
VC_CONTAINER_ERROR_OUT_OF_RESOURCES, /**< Out of resources (other than memory) */
|
||||
VC_CONTAINER_ERROR_EOS, /**< End of stream reached */
|
||||
VC_CONTAINER_ERROR_LIMIT_REACHED, /**< User defined limit reached (used when writing) */
|
||||
VC_CONTAINER_ERROR_BUFFER_TOO_SMALL, /**< Given buffer is too small for data to be copied */
|
||||
VC_CONTAINER_ERROR_INCOMPLETE_DATA, /**< Requested data is incomplete */
|
||||
VC_CONTAINER_ERROR_NO_TRACK_AVAILABLE, /**< Container doesn't have any track */
|
||||
VC_CONTAINER_ERROR_TRACK_FORMAT_NOT_SUPPORTED, /**< Format of the track is not supported */
|
||||
VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION, /**< The requested operation is not supported */
|
||||
VC_CONTAINER_ERROR_INVALID_ARGUMENT, /**< The argument provided is invalid */
|
||||
VC_CONTAINER_ERROR_CONTINUE, /**< The requested operation was interrupted and needs to be tried again */
|
||||
VC_CONTAINER_ERROR_ABORTED, /**< The requested operation was aborted */
|
||||
VC_CONTAINER_ERROR_NOT_FOUND, /**< The requested data was not found */
|
||||
VC_CONTAINER_ERROR_DRM_NOT_AUTHORIZED, /**< The DRM was not authorized */
|
||||
VC_CONTAINER_ERROR_DRM_EXPIRED, /**< The DRM has expired */
|
||||
VC_CONTAINER_ERROR_DRM_FAILED, /**< Generic DRM error */
|
||||
VC_CONTAINER_ERROR_FAILED, /**< Generic error */
|
||||
VC_CONTAINER_ERROR_NOT_READY /**< The container was not yet able to carry out the operation. */
|
||||
} VC_CONTAINER_STATUS_T;
|
||||
|
||||
/** Four Character Code type used to identify codecs, etc. */
|
||||
typedef uint32_t VC_CONTAINER_FOURCC_T;
|
||||
|
||||
/** Type definition for language codes.
|
||||
* Language are defined as ISO639 Alpha-3 codes (http://en.wikipedia.org/wiki/List_of_ISO_639-2_codes) */
|
||||
typedef uint8_t VC_CONTAINER_LANGUAGE_T[3];
|
||||
|
||||
/** Enumeration of the character encodings supported. */
|
||||
typedef enum {
|
||||
VC_CONTAINER_CHAR_ENCODING_UNKNOWN = 0, /**< Encoding is unknown */
|
||||
VC_CONTAINER_CHAR_ENCODING_UTF8 /**< UTF8 encoding */
|
||||
} VC_CONTAINER_CHAR_ENCODING_T;
|
||||
|
||||
/** \name Container Capabilities
|
||||
* The following flags are exported by containers to describe their capabilities */
|
||||
/* @{ */
|
||||
/** Type definition for container capabilities */
|
||||
typedef uint32_t VC_CONTAINER_CAPABILITIES_T;
|
||||
/** The container can seek */
|
||||
#define VC_CONTAINER_CAPS_CAN_SEEK 0x1
|
||||
/** Seeking is fast. The absence of this flag can be used as a hint to avoid seeking as much as possible */
|
||||
#define VC_CONTAINER_CAPS_SEEK_IS_FAST 0x2
|
||||
/** The container controls the pace at which it is reading the data */
|
||||
#define VC_CONTAINER_CAPS_CAN_CONTROL_PACE 0x4
|
||||
/** The container provides an index. This basically means that seeking will be precise and fast */
|
||||
#define VC_CONTAINER_CAPS_HAS_INDEX 0x8
|
||||
/** The container provides keyframe information */
|
||||
#define VC_CONTAINER_CAPS_DATA_HAS_KEYFRAME_FLAG 0x10
|
||||
/** The container supports adding tracks after TRACK_ADD_DONE control message has been sent */
|
||||
#define VC_CONTAINER_CAPS_DYNAMIC_TRACK_ADD 0x20
|
||||
/** The container supports forcing reading of a given track */
|
||||
#define VC_CONTAINER_CAPS_FORCE_TRACK 0x40
|
||||
/* @} */
|
||||
|
||||
/** \defgroup VcContainerMetadata Container Metadata
|
||||
* Container metadata contains descriptive information which is associated with the multimedia data */
|
||||
/* @{ */
|
||||
|
||||
/** Enumeration of the different metadata keys available. */
|
||||
typedef enum {
|
||||
/* Metadata of global scope */
|
||||
VC_CONTAINER_METADATA_KEY_TITLE = VC_FOURCC('t','i','t','l'),
|
||||
VC_CONTAINER_METADATA_KEY_ARTIST = VC_FOURCC('a','r','t','i'),
|
||||
VC_CONTAINER_METADATA_KEY_ALBUM = VC_FOURCC('a','l','b','m'),
|
||||
VC_CONTAINER_METADATA_KEY_DESCRIPTION = VC_FOURCC('d','e','s','c'),
|
||||
VC_CONTAINER_METADATA_KEY_YEAR = VC_FOURCC('y','e','a','r'),
|
||||
VC_CONTAINER_METADATA_KEY_GENRE = VC_FOURCC('g','e','n','r'),
|
||||
VC_CONTAINER_METADATA_KEY_TRACK = VC_FOURCC('t','r','a','k'),
|
||||
VC_CONTAINER_METADATA_KEY_LYRICS = VC_FOURCC('l','y','r','x'),
|
||||
|
||||
VC_CONTAINER_METADATA_KEY_UNKNOWN = 0
|
||||
|
||||
} VC_CONTAINER_METADATA_KEY_T;
|
||||
|
||||
/** Definition of the metadata type.
|
||||
* This type is used to store one element of metadata */
|
||||
typedef struct VC_CONTAINER_METADATA_T
|
||||
{
|
||||
/** Identifier for the type of metadata the value refers to.
|
||||
* Using an enum for the id will mean that a list of possible values will have to be
|
||||
* defined and maintained. This might limit extensibility and customisation.\n
|
||||
* Maybe it would be better to use a FOURCC or even a string here. */
|
||||
VC_CONTAINER_METADATA_KEY_T key;
|
||||
|
||||
VC_CONTAINER_LANGUAGE_T language; /**< Language code for the metadata */
|
||||
VC_CONTAINER_CHAR_ENCODING_T encoding; /**< Encoding of the metadata */
|
||||
|
||||
/** Metadata value. This value is defined as null-terminated UTF-8 string.\n
|
||||
* Do we want to support other types than strings (e.g. integer) ?\n
|
||||
* We need an encoding conversion library! */
|
||||
char *value;
|
||||
|
||||
/** Size of the memory area reserved for metadata value (including any
|
||||
* terminating characters). */
|
||||
unsigned int size;
|
||||
} VC_CONTAINER_METADATA_T;
|
||||
/* @} */
|
||||
|
||||
/** \defgroup VcContainerESFormat Container Elementary Stream Format
|
||||
* This describes the format of an elementary stream associated with a track */
|
||||
/* @{ */
|
||||
|
||||
/** Enumeration of the different types of elementary streams.
|
||||
* This divides elementary streams into 4 big categories. */
|
||||
typedef enum
|
||||
{
|
||||
VC_CONTAINER_ES_TYPE_UNKNOWN, /**< Unknown elementary stream type */
|
||||
VC_CONTAINER_ES_TYPE_AUDIO, /**< Audio elementary stream */
|
||||
VC_CONTAINER_ES_TYPE_VIDEO, /**< Video elementary stream */
|
||||
VC_CONTAINER_ES_TYPE_SUBPICTURE /**< Sub-picture elementary stream (e.g. subtitles, overlays) */
|
||||
|
||||
} VC_CONTAINER_ES_TYPE_T;
|
||||
|
||||
/** Definition of a video format.
|
||||
* This describes the properties specific to a video stream */
|
||||
typedef struct VC_CONTAINER_VIDEO_FORMAT_T
|
||||
{
|
||||
uint32_t width; /**< Width of the frame */
|
||||
uint32_t height; /**< Height of the frame */
|
||||
uint32_t visible_width; /**< Width of the visible area of the frame */
|
||||
uint32_t visible_height; /**< Height of the visible area of the frame */
|
||||
uint32_t x_offset; /**< Offset to the start of the visible width */
|
||||
uint32_t y_offset; /**< Offset to the start of the visible height */
|
||||
uint32_t frame_rate_num; /**< Frame rate numerator */
|
||||
uint32_t frame_rate_den; /**< Frame rate denominator */
|
||||
uint32_t par_num; /**< Pixel aspect ratio numerator */
|
||||
uint32_t par_den; /**< Pixel aspect ratio denominator */
|
||||
} VC_CONTAINER_VIDEO_FORMAT_T;
|
||||
|
||||
/** Enumeration for the different channel locations */
|
||||
typedef enum
|
||||
{
|
||||
VC_CONTAINER_AUDIO_CHANNEL_LEFT = 0, /**< Left channel */
|
||||
VC_CONTAINER_AUDIO_CHANNEL_RIGHT, /**< Right channel */
|
||||
VC_CONTAINER_AUDIO_CHANNEL_CENTER, /**< Center channel */
|
||||
VC_CONTAINER_AUDIO_CHANNEL_LOW_FREQUENCY, /**< Low frequency channel */
|
||||
VC_CONTAINER_AUDIO_CHANNEL_BACK_LEFT, /**< Back left channel */
|
||||
VC_CONTAINER_AUDIO_CHANNEL_BACK_RIGHT, /**< Back right channel */
|
||||
VC_CONTAINER_AUDIO_CHANNEL_BACK_CENTER, /**< Back center channel */
|
||||
VC_CONTAINER_AUDIO_CHANNEL_SIDE_LEFT, /**< Side left channel */
|
||||
VC_CONTAINER_AUDIO_CHANNEL_SIDE_RIGHT, /**< Side right channel */
|
||||
|
||||
VC_CONTAINER_AUDIO_CHANNELS_MAX = 32 /**< Maximum number of channels supported */
|
||||
|
||||
} VC_CONTAINER_AUDIO_CHANNEL_T;
|
||||
|
||||
/** \name Audio format flags
|
||||
* \anchor audioformatflags
|
||||
* The following flags describe properties of an audio stream */
|
||||
/* @{ */
|
||||
#define VC_CONTAINER_AUDIO_FORMAT_FLAG_CHANNEL_MAPPING 0x1 /**< Channel mapping available */
|
||||
/* @} */
|
||||
|
||||
/** Definition of an audio format.
|
||||
* This describes the properties specific to an audio stream */
|
||||
typedef struct VC_CONTAINER_AUDIO_FORMAT_T
|
||||
{
|
||||
uint32_t channels; /**< Number of audio channels */
|
||||
uint32_t sample_rate; /**< Sample rate */
|
||||
|
||||
uint32_t bits_per_sample; /**< Bits per sample */
|
||||
uint32_t block_align; /**< Size of a block of data */
|
||||
|
||||
uint32_t flags; /**< Flags describing the audio format.
|
||||
* See \ref audioformatflags "Audio format flags". */
|
||||
|
||||
/** Mapping of the channels in order of appearance */
|
||||
VC_CONTAINER_AUDIO_CHANNEL_T channel_mapping[VC_CONTAINER_AUDIO_CHANNELS_MAX];
|
||||
|
||||
uint16_t gap_delay; /**< Delay introduced by the encoder. Used for gapless playback */
|
||||
uint16_t gap_padding; /**< Padding introduced by the encoder. Used for gapless playback */
|
||||
|
||||
/** Replay gain information. First element is the track information and the second
|
||||
* is the album information. */
|
||||
struct {
|
||||
float peak; /**< Peak value (full range is 1.0) */
|
||||
float gain; /**< Gain value in dB */
|
||||
} replay_gain[2];
|
||||
|
||||
} VC_CONTAINER_AUDIO_FORMAT_T;
|
||||
|
||||
/** Definition of a subpicture format.
|
||||
* This describes the properties specific to a subpicture stream */
|
||||
typedef struct VC_CONTAINER_SUBPICTURE_FORMAT_T
|
||||
{
|
||||
VC_CONTAINER_CHAR_ENCODING_T encoding; /**< Encoding for text based subpicture formats */
|
||||
uint32_t x_offset; /**< Width offset to the start of the subpicture */
|
||||
uint32_t y_offset; /**< Height offset to the start of the subpicture */
|
||||
} VC_CONTAINER_SUBPICTURE_FORMAT_T;
|
||||
|
||||
/** \name Elementary stream format flags
|
||||
* \anchor esformatflags
|
||||
* The following flags describe properties of an elementary stream */
|
||||
/* @{ */
|
||||
#define VC_CONTAINER_ES_FORMAT_FLAG_FRAMED 0x1 /**< Elementary stream is framed */
|
||||
/* @} */
|
||||
|
||||
/** Definition of the type specific format.
|
||||
* This describes the type specific information of the elementary stream. */
|
||||
typedef union
|
||||
{
|
||||
VC_CONTAINER_AUDIO_FORMAT_T audio; /**< Audio specific information */
|
||||
VC_CONTAINER_VIDEO_FORMAT_T video; /**< Video specific information */
|
||||
VC_CONTAINER_SUBPICTURE_FORMAT_T subpicture; /**< Subpicture specific information */
|
||||
} VC_CONTAINER_ES_SPECIFIC_FORMAT_T;
|
||||
|
||||
/** Definition of an elementary stream format */
|
||||
typedef struct VC_CONTAINER_ES_FORMAT_T
|
||||
{
|
||||
VC_CONTAINER_ES_TYPE_T es_type; /**< Type of the elementary stream */
|
||||
VC_CONTAINER_FOURCC_T codec; /**< Coding of the elementary stream */
|
||||
VC_CONTAINER_FOURCC_T codec_variant; /**< If set, indicates a variant of the coding */
|
||||
|
||||
VC_CONTAINER_ES_SPECIFIC_FORMAT_T *type; /**< Type specific information for the elementary stream */
|
||||
|
||||
uint32_t bitrate; /**< Bitrate */
|
||||
|
||||
VC_CONTAINER_LANGUAGE_T language; /**< Language code for the elementary stream */
|
||||
uint32_t group_id; /**< ID of the group this elementary stream belongs to */
|
||||
|
||||
uint32_t flags; /**< Flags describing the properties of an elementary stream.
|
||||
* See \ref esformatflags "Elementary stream format flags". */
|
||||
|
||||
unsigned int extradata_size; /**< Size of the codec specific data */
|
||||
uint8_t *extradata; /**< Codec specific data */
|
||||
|
||||
} VC_CONTAINER_ES_FORMAT_T;
|
||||
/* @} */
|
||||
|
||||
/** \defgroup VcContainerPacket Container Packet
|
||||
* A container packet is the unit of data that is being read from or written to a container */
|
||||
/* @{ */
|
||||
|
||||
/** Structure describing a data packet */
|
||||
typedef struct VC_CONTAINER_PACKET_T
|
||||
{
|
||||
struct VC_CONTAINER_PACKET_T *next; /**< Used to build lists of packets */
|
||||
uint8_t *data; /**< Pointer to the buffer containing the actual data for the packet */
|
||||
unsigned int buffer_size; /**< Size of the p_data buffer. This is used to indicate how much data can be read in p_data */
|
||||
unsigned int size; /**< Size of the data contained in p_data */
|
||||
unsigned int frame_size; /**< If set, indicates the size of the frame this packet belongs to */
|
||||
int64_t pts; /**< Presentation Timestamp of the packet */
|
||||
int64_t dts; /**< Decoding Timestamp of the packet */
|
||||
uint64_t num; /**< Number of this packet */
|
||||
uint32_t track; /**< Track associated with this packet */
|
||||
uint32_t flags; /**< Flags associated with this packet */
|
||||
|
||||
void *user_data; /**< Field reserved for use by the client */
|
||||
void *framework_data; /**< Field reserved for use by the framework */
|
||||
|
||||
} VC_CONTAINER_PACKET_T;
|
||||
|
||||
/** \name Container Packet Flags
|
||||
* The following flags describe properties of the data packet */
|
||||
/* @{ */
|
||||
#define VC_CONTAINER_PACKET_FLAG_KEYFRAME 0x01 /**< Packet is a keyframe */
|
||||
#define VC_CONTAINER_PACKET_FLAG_FRAME_START 0x02 /**< Packet starts a frame */
|
||||
#define VC_CONTAINER_PACKET_FLAG_FRAME_END 0x04 /**< Packet ends a frame */
|
||||
#define VC_CONTAINER_PACKET_FLAG_FRAME 0x06 /**< Packet contains only complete frames */
|
||||
#define VC_CONTAINER_PACKET_FLAG_DISCONTINUITY 0x08 /**< Packet comes after a discontinuity in the stream. Decoders might have to be flushed */
|
||||
#define VC_CONTAINER_PACKET_FLAG_ENCRYPTED 0x10 /**< Packet contains DRM encrypted data */
|
||||
#define VC_CONTAINER_PACKET_FLAG_CONFIG 0x20 /**< Packet contains stream specific config data */
|
||||
/* @} */
|
||||
|
||||
/** \name Special Unknown Time Value
|
||||
* This is the special value used to signal that a timestamp is not known */
|
||||
/* @{ */
|
||||
#define VC_CONTAINER_TIME_UNKNOWN (INT64_C(1)<<63) /**< Special value for signalling that time is not known */
|
||||
/* @} */
|
||||
|
||||
/* @} */
|
||||
|
||||
/** \name Track flags
|
||||
* \anchor trackflags
|
||||
* The following flags describe properties of a track */
|
||||
/* @{ */
|
||||
#define VC_CONTAINER_TRACK_FLAG_CHANGED 0x1 /**< Track definition has changed */
|
||||
/* @} */
|
||||
|
||||
/** Definition of the track type */
|
||||
typedef struct VC_CONTAINER_TRACK_T
|
||||
{
|
||||
struct VC_CONTAINER_TRACK_PRIVATE_T *priv; /**< Private member used by the implementation */
|
||||
uint32_t is_enabled; /**< Flag to specify if the track is enabled */
|
||||
uint32_t flags; /**< Flags describing the properties of a track.
|
||||
* See \ref trackflags "Track flags". */
|
||||
|
||||
VC_CONTAINER_ES_FORMAT_T *format; /**< Format of the elementary stream contained in the track */
|
||||
|
||||
unsigned int meta_num; /**< Number of metadata elements associated with the track */
|
||||
VC_CONTAINER_METADATA_T **meta; /**< Array of metadata elements associated with the track */
|
||||
|
||||
} VC_CONTAINER_TRACK_T;
|
||||
|
||||
/** Definition of the DRM type */
|
||||
typedef struct VC_CONTAINER_DRM_T
|
||||
{
|
||||
VC_CONTAINER_FOURCC_T format; /**< Four character code describing the format of the DRM in use */
|
||||
unsigned int views_max; /**< Maximum number of views allowed */
|
||||
unsigned int views_current; /**< Current number of views */
|
||||
|
||||
} VC_CONTAINER_DRM_T;
|
||||
|
||||
/** Type definition for the progress reporting function. This function will be called regularly
|
||||
* by the container during a call which blocks for too long and will report the progress of the
|
||||
* operation as an estimated total length in microseconds and a percentage done.
|
||||
* Returning anything else than VC_CONTAINER_SUCCESS in this function will abort the current
|
||||
* operation. */
|
||||
typedef VC_CONTAINER_STATUS_T (*VC_CONTAINER_PROGRESS_REPORT_FUNC_T)(void *userdata,
|
||||
int64_t length, unsigned int percentage_done);
|
||||
|
||||
/** \name Container Events
|
||||
* The following flags are exported by containers to notify the application of events */
|
||||
/* @{ */
|
||||
/** Type definition for container events */
|
||||
typedef uint32_t VC_CONTAINER_EVENTS_T;
|
||||
#define VC_CONTAINER_EVENT_TRACKS_CHANGE 1 /**< Track information has changed */
|
||||
#define VC_CONTAINER_EVENT_METADATA_CHANGE 2 /**< Metadata has changed */
|
||||
/* @} */
|
||||
|
||||
/** Definition of the container context */
|
||||
typedef struct VC_CONTAINER_T
|
||||
{
|
||||
struct VC_CONTAINER_PRIVATE_T *priv; /**< Private member used by the implementation */
|
||||
|
||||
VC_CONTAINER_EVENTS_T events; /**< Events generated by the container */
|
||||
VC_CONTAINER_CAPABILITIES_T capabilities; /**< Capabilities exported by the container */
|
||||
|
||||
VC_CONTAINER_PROGRESS_REPORT_FUNC_T pf_progress; /**< Progress report function pointer */
|
||||
void *progress_userdata; /**< Progress report user data */
|
||||
|
||||
int64_t duration; /**< Duration of the media in microseconds */
|
||||
int64_t position; /**< Current time position into the media */
|
||||
int64_t size; /**< Size of the media in bytes */
|
||||
|
||||
unsigned int tracks_num; /**< Number of tracks available */
|
||||
/** Pointer to an array of pointers to track elements.
|
||||
* The reasoning for using a pointer to pointers here is to allow us to extend
|
||||
* VC_CONTAINER_TRACK_T without losing binary backward compatibility. */
|
||||
VC_CONTAINER_TRACK_T **tracks;
|
||||
|
||||
unsigned int meta_num; /**< Number of metadata elements associated with the container */
|
||||
VC_CONTAINER_METADATA_T **meta; /**< Array of metadata elements associated with the container */
|
||||
|
||||
VC_CONTAINER_DRM_T *drm; /**< Description used for DRM protected content */
|
||||
|
||||
} VC_CONTAINER_T;
|
||||
|
||||
/** Forward declaration of a container input / output context.
|
||||
* This structure defines the context for a container io instance */
|
||||
typedef struct VC_CONTAINER_IO_T VC_CONTAINER_IO_T;
|
||||
|
||||
/** Opens the media container pointed to by the URI for reading.
|
||||
* This will create an an instance of a container reader and its associated context.
|
||||
* The context returned will also be filled with the information retrieved from the media.
|
||||
*
|
||||
* If the media isn't accessible or recognized, this will return a null pointer as well as
|
||||
* an error code indicating why this failed.
|
||||
*
|
||||
* \param psz_uri Unified Resource Identifier pointing to the media container
|
||||
* \param status Returns the status of the operation
|
||||
* \param pf_progress User provided function pointer to a progress report function. Can be set to
|
||||
* null if no progress report is wanted. This function will be used during
|
||||
* the whole lifetime of the instance (i.e. it will be used during
|
||||
* open / seek / close)
|
||||
* \param progress_userdata User provided pointer that will be passed during the progress report
|
||||
* function call.
|
||||
* \return A pointer to the context of the new instance of the
|
||||
* container reader. Returns NULL on failure.
|
||||
*/
|
||||
VC_CONTAINER_T *vc_container_open_reader( const char *psz_uri, VC_CONTAINER_STATUS_T *status,
|
||||
VC_CONTAINER_PROGRESS_REPORT_FUNC_T pf_progress, void *progress_userdata);
|
||||
|
||||
/** Opens for reading the media container pointed to by the container i/o.
|
||||
* This will create an an instance of a container reader and its associated context.
|
||||
* The context returned will also be filled with the information retrieved from the media.
|
||||
*
|
||||
* If the media isn't accessible or recognized, this will return a null pointer as well as
|
||||
* an error code indicating why this failed.
|
||||
*
|
||||
* \param p_io Instance of the container i/o to use
|
||||
* \param psz_uri Unified Resource Identifier pointing to the media container (optional)
|
||||
* \param status Returns the status of the operation
|
||||
* \param pf_progress User provided function pointer to a progress report function. Can be set to
|
||||
* null if no progress report is wanted. This function will be used during
|
||||
* the whole lifetime of the instance (i.e. it will be used during
|
||||
* open / seek / close)
|
||||
* \param progress_userdata User provided pointer that will be passed during the progress report
|
||||
* function call.
|
||||
* \return A pointer to the context of the new instance of the
|
||||
* container reader. Returns NULL on failure.
|
||||
*/
|
||||
VC_CONTAINER_T *vc_container_open_reader_with_io( VC_CONTAINER_IO_T *p_io,
|
||||
const char *psz_uri, VC_CONTAINER_STATUS_T *status,
|
||||
VC_CONTAINER_PROGRESS_REPORT_FUNC_T pf_progress, void *progress_userdata);
|
||||
|
||||
/** Opens the media container pointed to by the URI for writing.
|
||||
* This will create an an instance of a container writer and its associated context.
|
||||
* The context returned will be initialised to sensible values.
|
||||
*
|
||||
* The application will need to add all the media tracks using \ref vc_container_control before
|
||||
* it starts writing data using \ref vc_container_write.
|
||||
*
|
||||
* If the media isn't accessible or recognized, this will return a null pointer as well as
|
||||
* an error code indicating why this failed.
|
||||
*
|
||||
* \param psz_uri Unified Resource Identifier pointing to the media container
|
||||
* \param status Returns the status of the operation
|
||||
* \param pf_progress User provided function pointer to a progess report function. Can be set to
|
||||
* null if no progress report is wanted.
|
||||
* \param progress_userdata User provided pointer that will be passed during the progress report
|
||||
* function call.
|
||||
* \return A pointer to the context of the new instance of the
|
||||
* container writer. Returns NULL on failure.
|
||||
*/
|
||||
VC_CONTAINER_T *vc_container_open_writer( const char *psz_uri, VC_CONTAINER_STATUS_T *status,
|
||||
VC_CONTAINER_PROGRESS_REPORT_FUNC_T pf_progress, void *progress_userdata);
|
||||
|
||||
/** Closes an instance of a container reader / writer.
|
||||
* This will free all the resources associated with the context.
|
||||
*
|
||||
* \param context Pointer to the context of the instance to close
|
||||
* \return the status of the operation
|
||||
*/
|
||||
VC_CONTAINER_STATUS_T vc_container_close( VC_CONTAINER_T *context );
|
||||
|
||||
/** \name Container read flags
|
||||
* The following flags can be passed during a read call */
|
||||
/* @{ */
|
||||
/** Type definition for the read flags */
|
||||
typedef uint32_t VC_CONTAINER_READ_FLAGS_T;
|
||||
/** Ask the container to only return information on the next packet without reading it */
|
||||
#define VC_CONTAINER_READ_FLAG_INFO 1
|
||||
/** Ask the container to skip the next packet */
|
||||
#define VC_CONTAINER_READ_FLAG_SKIP 2
|
||||
/** Force the container to read data from the specified track */
|
||||
#define VC_CONTAINER_READ_FLAG_FORCE_TRACK 4
|
||||
/* @} */
|
||||
|
||||
/** Reads a data packet from a container reader.
|
||||
* By default, the reader will read whatever packet comes next in the container and update the
|
||||
* given \ref VC_CONTAINER_PACKET_T structure with this packet's information.
|
||||
* This behaviour can be changed using the \ref VC_CONTAINER_READ_FLAGS_T.\n
|
||||
* \ref VC_CONTAINER_READ_FLAG_INFO will instruct the reader to only return information on the
|
||||
* following packet but not its actual data. The data can be retreived later by issuing another
|
||||
* read request.\n
|
||||
* \ref VC_CONTAINER_READ_FLAG_FORCE_TRACK will force the reader to read the next packet for the
|
||||
* selected track (as present in the \ref VC_CONTAINER_PACKET_T structure) instead of defaulting
|
||||
* to reading the packet which comes next in the container.\n
|
||||
* \ref VC_CONTAINER_READ_FLAG_SKIP will instruct the reader to skip the next packet. In this case
|
||||
* it isn't necessary for the caller to pass a pointer to a \ref VC_CONTAINER_PACKET_T structure
|
||||
* unless the \ref VC_CONTAINER_READ_FLAG_INFO is also given.\n
|
||||
* A combination of all these flags can be used.
|
||||
*
|
||||
* \param context Pointer to the context of the reader to use
|
||||
* \param packet Pointer to the VC_CONTAINER_PACKET_T structure describing the data packet
|
||||
* This needs to be partially filled before the call (buffer, buffer_size)
|
||||
* \param flags Flags controlling the read operation
|
||||
* \return the status of the operation
|
||||
*/
|
||||
VC_CONTAINER_STATUS_T vc_container_read( VC_CONTAINER_T *context,
|
||||
VC_CONTAINER_PACKET_T *packet, VC_CONTAINER_READ_FLAGS_T flags );
|
||||
|
||||
/** Writes a data packet to a container writer.
|
||||
*
|
||||
* \param context Pointer to the context of the writer to use
|
||||
* \param packet Pointer to the VC_CONTAINER_PACKET_T structure describing the data packet
|
||||
* \return the status of the operation
|
||||
*/
|
||||
VC_CONTAINER_STATUS_T vc_container_write( VC_CONTAINER_T *context,
|
||||
VC_CONTAINER_PACKET_T *packet );
|
||||
|
||||
/** Definition of the different seek modes */
|
||||
typedef enum
|
||||
{
|
||||
/** The offset provided for seeking is an absolute time offset in microseconds */
|
||||
VC_CONTAINER_SEEK_MODE_TIME = 0,
|
||||
/** The offset provided for seeking is a percentage (Q32 ?) */
|
||||
VC_CONTAINER_SEEK_MODE_PERCENT
|
||||
|
||||
} VC_CONTAINER_SEEK_MODE_T;
|
||||
|
||||
/** \name Container Seek Flags
|
||||
* The following flags control seek operations */
|
||||
/* @{ */
|
||||
/** Type definition for the seek flags */
|
||||
typedef uint32_t VC_CONTAINER_SEEK_FLAGS_T;
|
||||
/** Choose precise seeking even if slower */
|
||||
#define VC_CONTAINER_SEEK_FLAG_PRECISE 0x1
|
||||
/** By default a seek will always seek to the keyframe which comes just before the requested
|
||||
* position. This flag allows the caller to force the container to seek to the keyframe which
|
||||
* comes just after the requested position. */
|
||||
#define VC_CONTAINER_SEEK_FLAG_FORWARD 0x2
|
||||
/* @} */
|
||||
|
||||
/** Seek into a container reader.
|
||||
*
|
||||
* \param context Pointer to the context of the reader to use
|
||||
* \param offset Offset to seek to. Used as an input as well as output value.
|
||||
* \param mode Seeking mode requested.
|
||||
* \param flags Flags affecting the seeking operation.
|
||||
* \return the status of the operation
|
||||
*/
|
||||
VC_CONTAINER_STATUS_T vc_container_seek( VC_CONTAINER_T *context, int64_t *offset,
|
||||
VC_CONTAINER_SEEK_MODE_T mode, VC_CONTAINER_SEEK_FLAGS_T flags);
|
||||
|
||||
/** Performance statistics.
|
||||
*/
|
||||
/** The maximum number of bins a statistics value is held in */
|
||||
#define VC_CONTAINER_STATS_BINS 10
|
||||
|
||||
/** This type is used to represent multiple values of a statistic.
|
||||
*/
|
||||
typedef struct VC_CONTAINER_STATS_T
|
||||
{
|
||||
/** The number of places to right shift count before using. Resulting values
|
||||
* of zero are rounded to 1. */
|
||||
uint32_t shift;
|
||||
|
||||
/** We store VC_CONTAINER_STATS_BINS+1 records, in sorted order of numpc.
|
||||
* At least one will be invalid and all zero. We combine adjacent records
|
||||
* as necessary. */
|
||||
struct {
|
||||
/** Sum of count. For single value statistics this is the freqency, for paired statistics
|
||||
* this is the number of bytes written. */
|
||||
uint32_t count;
|
||||
/** Number of count. For single value statistics this is the total value, for paired statistics
|
||||
* this is the total length of time. */
|
||||
uint32_t num;
|
||||
/** Number>>shift per count. Stored to save recalculation. */
|
||||
uint32_t numpc;
|
||||
} record[VC_CONTAINER_STATS_BINS+1];
|
||||
} VC_CONTAINER_STATS_T;
|
||||
|
||||
/** This type represents the statistics saved by the io layer. */
|
||||
typedef struct VC_CONTAINER_WRITE_STATS_T
|
||||
{
|
||||
/** This logs the number of bytes written in count, and the microseconds taken to write
|
||||
* in num. */
|
||||
VC_CONTAINER_STATS_T write;
|
||||
/** This logs the length of time the write function has to wait for the asynchronous task. */
|
||||
VC_CONTAINER_STATS_T wait;
|
||||
/** This logs the length of time that we wait for a flush command to complete. */
|
||||
VC_CONTAINER_STATS_T flush;
|
||||
} VC_CONTAINER_WRITE_STATS_T;
|
||||
|
||||
|
||||
/** Control operations which can be done on containers. */
|
||||
typedef enum
|
||||
{
|
||||
/** Adds a new track to the list of tracks. This should be used by writers to create
|
||||
* their list of tracks.\n
|
||||
* Arguments:\n
|
||||
* arg1= VC_CONTAINER_ES_FORMAT_T *: format of the track to add\n
|
||||
* return= VC_CONTAINER_ERROR_TRACK_FORMAT_NOT_SUPPORTED if the format is not supported */
|
||||
VC_CONTAINER_CONTROL_TRACK_ADD = 0,
|
||||
|
||||
/** Specifies that we're done adding new tracks. This is optional but can be used by writers
|
||||
* to trigger the writing of the container header early. If this isn't used, the header will be
|
||||
* written when the first data packet is received.\n
|
||||
* No arguments.\n
|
||||
* return= VC_CONTAINER_ERROR_TRACK_FORMAT_NOT_SUPPORTED if the format is not supported */
|
||||
VC_CONTAINER_CONTROL_TRACK_ADD_DONE,
|
||||
|
||||
/** Change the format of a track in the list of tracks. This should be used by writers to modify
|
||||
* the format of a track at run-time.\n
|
||||
* Arguments:\n
|
||||
* arg1= unsigned int: index of track to change\n
|
||||
* arg2= VC_CONTAINER_ES_FORMAT_T *: format of the track to add\n
|
||||
* return= VC_CONTAINER_ERROR_TRACK_FORMAT_NOT_SUPPORTED if the format is not supported */
|
||||
VC_CONTAINER_CONTROL_TRACK_CHANGE,
|
||||
|
||||
/** Deletes a track from the list of tracks. This should be used by writers to delete tracks
|
||||
* during run-time. Note that vc_container_close will automatically delete all track so it
|
||||
* isn't necessary to call this before closing a writer.\n
|
||||
* Arguments:\n
|
||||
* arg1= index of the track to delete */
|
||||
VC_CONTAINER_CONTROL_TRACK_DEL,
|
||||
|
||||
/** Activate the playback of DRM protected content.\n
|
||||
* No arguments.\n
|
||||
* return= one of the VC_CONTAINER_ERROR_DRM error codes if content can't be played */
|
||||
VC_CONTAINER_CONTROL_DRM_PLAY,
|
||||
|
||||
/** TBD */
|
||||
VC_CONTAINER_CONTROL_METADATA_ADD,
|
||||
/** TBD */
|
||||
VC_CONTAINER_CONTROL_METADATA_CHANGE,
|
||||
/** TBD */
|
||||
VC_CONTAINER_CONTROL_METADATA_DEL,
|
||||
|
||||
/** TBD */
|
||||
VC_CONTAINER_CONTROL_CHAPTER_ADD,
|
||||
/** TBD */
|
||||
VC_CONTAINER_CONTROL_CHAPTER_DEL,
|
||||
|
||||
/** Set a maximum size for files generated by writers.\n
|
||||
* Arguments:\n
|
||||
* arg1= uint64_t: maximum size */
|
||||
VC_CONTAINER_CONTROL_SET_MAXIMUM_SIZE,
|
||||
|
||||
/** Enables/disabled performance statistic gathering.\n
|
||||
* Arguments:\n
|
||||
* arg1= bool: enable or disable */
|
||||
VC_CONTAINER_CONTROL_SET_IO_PERF_STATS,
|
||||
|
||||
/** Collects performance statistics.\n
|
||||
* Arguments:\n
|
||||
* arg1= VC_CONTAINER_WRITE_STATS_T *: */
|
||||
VC_CONTAINER_CONTROL_GET_IO_PERF_STATS,
|
||||
|
||||
/** HACK.\n
|
||||
* Arguments:\n
|
||||
* arg1= void (*)(void *): callback function
|
||||
* arg1= void *: opaque pointer to pass during the callback */
|
||||
VC_CONTAINER_CONTROL_SET_IO_BUFFER_FULL_CALLBACK,
|
||||
|
||||
/** Set the I/O read buffer size to be used.\n
|
||||
* Arguments:\n
|
||||
* arg1= uint32_t: New buffer size in bytes*/
|
||||
VC_CONTAINER_CONTROL_IO_SET_READ_BUFFER_SIZE,
|
||||
|
||||
/** Set the timeout on I/O read operations, if applicable.\n
|
||||
* Arguments:\n
|
||||
* arg1= uint32_t: New timeout in milliseconds, or VC_CONTAINER_READ_TIMEOUT_BLOCK */
|
||||
VC_CONTAINER_CONTROL_IO_SET_READ_TIMEOUT_MS,
|
||||
|
||||
/** Set the timestamp base.\n
|
||||
* The timestamp passed equates to time zero for the stream.\n
|
||||
* Arguments:\n
|
||||
* arg1= uint32_t: Timestamp base in stream clock units. */
|
||||
VC_CONTAINER_CONTROL_SET_TIMESTAMP_BASE,
|
||||
|
||||
/** Set the next expected sequence number for the stream.\n
|
||||
* Arguments:\n
|
||||
* arg1= uint32_t: Next expected sequence number. */
|
||||
VC_CONTAINER_CONTROL_SET_NEXT_SEQUENCE_NUMBER,
|
||||
|
||||
/** Set the source ID for the container.\n
|
||||
* Arguments:\n
|
||||
* arg1= uint32_t: Source identifier. */
|
||||
VC_CONTAINER_CONTROL_SET_SOURCE_ID,
|
||||
|
||||
/** Arguments:\n
|
||||
* arg1= void *: metadata buffer
|
||||
* arg2= unsigned long: length of metadata in bytes */
|
||||
VC_CONTAINER_CONTROL_GET_DRM_METADATA,
|
||||
|
||||
/** Arguments:\n
|
||||
* arg1= unsigned long: track number
|
||||
* arg2= VC_CONTAINER_FOURCC_T : drm type
|
||||
* arg3= void *: encryption configuration parameters.
|
||||
* arg4= unsigned long: configuration data length */
|
||||
VC_CONTAINER_CONTROL_ENCRYPT_TRACK,
|
||||
|
||||
/** Causes the io to be flushed.\n
|
||||
* Arguments: none */
|
||||
VC_CONTAINER_CONTROL_IO_FLUSH,
|
||||
|
||||
/** Request the container reader to packetize data for the specified track.
|
||||
* Arguments:\n
|
||||
* arg1= unsigned long: track number
|
||||
* arg2= VC_CONTAINER_FOURCC_T: codec variant to output */
|
||||
VC_CONTAINER_CONTROL_TRACK_PACKETIZE,
|
||||
|
||||
/** Private user extensions must be above this number */
|
||||
VC_CONTAINER_CONTROL_USER_EXTENSIONS = 0x1000
|
||||
|
||||
} VC_CONTAINER_CONTROL_T;
|
||||
|
||||
/** Used with the VC_CONTAINER_CONTROL_IO_SET_READ_TIMEOUT_MS control to indicate the read shall
|
||||
* block until either data is available, or an error occurs.
|
||||
*/
|
||||
#define VC_CONTAINER_READ_TIMEOUT_BLOCK (uint32_t)(-1)
|
||||
|
||||
/** Extensible control function for container readers and writers.
|
||||
* This function takes a variable number of arguments which will depend on the specific operation.
|
||||
*
|
||||
* \param context Pointer to the VC_CONTAINER_T context to use
|
||||
* \param operation The requested operation
|
||||
* \return the status of the operation. Can be \ref VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION
|
||||
* if the operation is not supported or implemented by the container.
|
||||
*/
|
||||
VC_CONTAINER_STATUS_T vc_container_control( VC_CONTAINER_T *context, VC_CONTAINER_CONTROL_T operation, ... );
|
||||
|
||||
/* @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* VC_CONTAINERS_H */
|
214
gfx/include/userland/containers/containers_codecs.h
Normal file
214
gfx/include/userland/containers/containers_codecs.h
Normal file
@ -0,0 +1,214 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef VC_CONTAINERS_CODECS_H
|
||||
#define VC_CONTAINERS_CODECS_H
|
||||
|
||||
/** \file containers_codecs.h
|
||||
* Codec helpers
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "containers/containers_types.h"
|
||||
|
||||
/* Video */
|
||||
#define VC_CONTAINER_CODEC_MP1V VC_FOURCC('m','p','1','v')
|
||||
#define VC_CONTAINER_CODEC_MP2V VC_FOURCC('m','p','2','v')
|
||||
#define VC_CONTAINER_CODEC_MP4V VC_FOURCC('m','p','4','v')
|
||||
#define VC_CONTAINER_CODEC_DIV3 VC_FOURCC('d','i','v','3')
|
||||
#define VC_CONTAINER_CODEC_DIV4 VC_FOURCC('d','i','v','4')
|
||||
#define VC_CONTAINER_CODEC_H263 VC_FOURCC('h','2','6','3')
|
||||
#define VC_CONTAINER_CODEC_H264 VC_FOURCC('h','2','6','4')
|
||||
#define VC_CONTAINER_CODEC_MVC VC_FOURCC('m','v','c',' ')
|
||||
#define VC_CONTAINER_CODEC_WMV1 VC_FOURCC('w','m','v','1')
|
||||
#define VC_CONTAINER_CODEC_WMV2 VC_FOURCC('w','m','v','2')
|
||||
#define VC_CONTAINER_CODEC_WMV3 VC_FOURCC('w','m','v','3')
|
||||
#define VC_CONTAINER_CODEC_WVC1 VC_FOURCC('w','v','c','1')
|
||||
#define VC_CONTAINER_CODEC_WMVA VC_FOURCC('w','m','v','a')
|
||||
#define VC_CONTAINER_CODEC_MJPEG VC_FOURCC('m','j','p','g')
|
||||
#define VC_CONTAINER_CODEC_MJPEGA VC_FOURCC('m','j','p','a')
|
||||
#define VC_CONTAINER_CODEC_MJPEGB VC_FOURCC('m','j','p','b')
|
||||
#define VC_CONTAINER_CODEC_THEORA VC_FOURCC('t','h','e','o')
|
||||
#define VC_CONTAINER_CODEC_VP3 VC_FOURCC('v','p','3',' ')
|
||||
#define VC_CONTAINER_CODEC_VP6 VC_FOURCC('v','p','6',' ')
|
||||
#define VC_CONTAINER_CODEC_VP7 VC_FOURCC('v','p','7',' ')
|
||||
#define VC_CONTAINER_CODEC_VP8 VC_FOURCC('v','p','8',' ')
|
||||
#define VC_CONTAINER_CODEC_RV10 VC_FOURCC('r','v','1','0')
|
||||
#define VC_CONTAINER_CODEC_RV20 VC_FOURCC('r','v','2','0')
|
||||
#define VC_CONTAINER_CODEC_RV30 VC_FOURCC('r','v','3','0')
|
||||
#define VC_CONTAINER_CODEC_RV40 VC_FOURCC('r','v','4','0')
|
||||
#define VC_CONTAINER_CODEC_AVS VC_FOURCC('a','v','s',' ')
|
||||
#define VC_CONTAINER_CODEC_SPARK VC_FOURCC('s','p','r','k')
|
||||
#define VC_CONTAINER_CODEC_DIRAC VC_FOURCC('d','r','a','c')
|
||||
|
||||
#define VC_CONTAINER_CODEC_YUV VC_FOURCC('y','u','v',' ')
|
||||
#define VC_CONTAINER_CODEC_I420 VC_FOURCC('I','4','2','0')
|
||||
#define VC_CONTAINER_CODEC_YV12 VC_FOURCC('Y','V','1','2')
|
||||
#define VC_CONTAINER_CODEC_I422 VC_FOURCC('I','4','2','2')
|
||||
#define VC_CONTAINER_CODEC_YUYV VC_FOURCC('Y','U','Y','V')
|
||||
#define VC_CONTAINER_CODEC_YVYU VC_FOURCC('Y','V','Y','U')
|
||||
#define VC_CONTAINER_CODEC_UYVY VC_FOURCC('U','Y','V','Y')
|
||||
#define VC_CONTAINER_CODEC_VYUY VC_FOURCC('V','Y','U','Y')
|
||||
#define VC_CONTAINER_CODEC_NV12 VC_FOURCC('N','V','1','2')
|
||||
#define VC_CONTAINER_CODEC_NV21 VC_FOURCC('N','V','2','1')
|
||||
#define VC_CONTAINER_CODEC_ARGB VC_FOURCC('A','R','G','B')
|
||||
#define VC_CONTAINER_CODEC_RGBA VC_FOURCC('R','G','B','A')
|
||||
#define VC_CONTAINER_CODEC_ABGR VC_FOURCC('A','B','G','R')
|
||||
#define VC_CONTAINER_CODEC_BGRA VC_FOURCC('B','G','R','A')
|
||||
#define VC_CONTAINER_CODEC_RGB16 VC_FOURCC('R','G','B','2')
|
||||
#define VC_CONTAINER_CODEC_RGB24 VC_FOURCC('R','G','B','3')
|
||||
#define VC_CONTAINER_CODEC_RGB32 VC_FOURCC('R','G','B','4')
|
||||
#define VC_CONTAINER_CODEC_BGR16 VC_FOURCC('B','G','R','2')
|
||||
#define VC_CONTAINER_CODEC_BGR24 VC_FOURCC('B','G','R','3')
|
||||
#define VC_CONTAINER_CODEC_BGR32 VC_FOURCC('B','G','R','4')
|
||||
#define VC_CONTAINER_CODEC_YUVUV128 VC_FOURCC('S','A','N','D')
|
||||
|
||||
#define VC_CONTAINER_CODEC_JPEG VC_FOURCC('j','p','e','g')
|
||||
#define VC_CONTAINER_CODEC_PNG VC_FOURCC('p','n','g',' ')
|
||||
#define VC_CONTAINER_CODEC_GIF VC_FOURCC('g','i','f',' ')
|
||||
#define VC_CONTAINER_CODEC_PPM VC_FOURCC('p','p','m',' ')
|
||||
#define VC_CONTAINER_CODEC_TGA VC_FOURCC('t','g','a',' ')
|
||||
#define VC_CONTAINER_CODEC_BMP VC_FOURCC('b','m','p',' ')
|
||||
|
||||
/* Audio */
|
||||
#define VC_CONTAINER_CODEC_PCM_UNSIGNED_BE VC_FOURCC('P','C','M','U')
|
||||
#define VC_CONTAINER_CODEC_PCM_UNSIGNED_LE VC_FOURCC('p','c','m','u')
|
||||
#define VC_CONTAINER_CODEC_PCM_SIGNED_BE VC_FOURCC('P','C','M','S')
|
||||
#define VC_CONTAINER_CODEC_PCM_SIGNED_LE VC_FOURCC('p','c','m','s')
|
||||
#define VC_CONTAINER_CODEC_PCM_FLOAT_BE VC_FOURCC('P','C','M','F')
|
||||
#define VC_CONTAINER_CODEC_PCM_FLOAT_LE VC_FOURCC('p','c','m','f')
|
||||
/* Defines for native endianness */
|
||||
#ifdef VC_CONTAINER_IS_BIG_ENDIAN
|
||||
#define VC_CONTAINER_CODEC_PCM_UNSIGNED VC_CONTAINER_CODEC_PCM_UNSIGNED_BE
|
||||
#define VC_CONTAINER_CODEC_PCM_SIGNED VC_CONTAINER_CODEC_PCM_SIGNED_BE
|
||||
#define VC_CONTAINER_CODEC_PCM_FLOAT VC_CONTAINER_CODEC_PCM_FLOAT_BE
|
||||
#else
|
||||
#define VC_CONTAINER_CODEC_PCM_UNSIGNED VC_CONTAINER_CODEC_PCM_UNSIGNED_LE
|
||||
#define VC_CONTAINER_CODEC_PCM_SIGNED VC_CONTAINER_CODEC_PCM_SIGNED_LE
|
||||
#define VC_CONTAINER_CODEC_PCM_FLOAT VC_CONTAINER_CODEC_PCM_FLOAT_LE
|
||||
#endif
|
||||
|
||||
#define VC_CONTAINER_CODEC_MPGA VC_FOURCC('m','p','g','a')
|
||||
#define VC_CONTAINER_CODEC_MP4A VC_FOURCC('m','p','4','a')
|
||||
#define VC_CONTAINER_CODEC_ALAW VC_FOURCC('a','l','a','w')
|
||||
#define VC_CONTAINER_CODEC_MULAW VC_FOURCC('u','l','a','w')
|
||||
#define VC_CONTAINER_CODEC_ADPCM_MS VC_FOURCC('m','s',0x0,0x2)
|
||||
#define VC_CONTAINER_CODEC_ADPCM_IMA_MS VC_FOURCC('m','s',0x0,0x1)
|
||||
#define VC_CONTAINER_CODEC_ADPCM_SWF VC_FOURCC('a','s','w','f')
|
||||
#define VC_CONTAINER_CODEC_WMA1 VC_FOURCC('w','m','a','1')
|
||||
#define VC_CONTAINER_CODEC_WMA2 VC_FOURCC('w','m','a','2')
|
||||
#define VC_CONTAINER_CODEC_WMAP VC_FOURCC('w','m','a','p')
|
||||
#define VC_CONTAINER_CODEC_WMAL VC_FOURCC('w','m','a','l')
|
||||
#define VC_CONTAINER_CODEC_WMAV VC_FOURCC('w','m','a','v')
|
||||
#define VC_CONTAINER_CODEC_AMRNB VC_FOURCC('a','m','r','n')
|
||||
#define VC_CONTAINER_CODEC_AMRWB VC_FOURCC('a','m','r','w')
|
||||
#define VC_CONTAINER_CODEC_AMRWBP VC_FOURCC('a','m','r','p')
|
||||
#define VC_CONTAINER_CODEC_AC3 VC_FOURCC('a','c','3',' ')
|
||||
#define VC_CONTAINER_CODEC_EAC3 VC_FOURCC('e','a','c','3')
|
||||
#define VC_CONTAINER_CODEC_DTS VC_FOURCC('d','t','s',' ')
|
||||
#define VC_CONTAINER_CODEC_MLP VC_FOURCC('m','l','p',' ')
|
||||
#define VC_CONTAINER_CODEC_FLAC VC_FOURCC('f','l','a','c')
|
||||
#define VC_CONTAINER_CODEC_VORBIS VC_FOURCC('v','o','r','b')
|
||||
#define VC_CONTAINER_CODEC_SPEEX VC_FOURCC('s','p','x',' ')
|
||||
#define VC_CONTAINER_CODEC_ATRAC3 VC_FOURCC('a','t','r','3')
|
||||
#define VC_CONTAINER_CODEC_ATRACX VC_FOURCC('a','t','r','x')
|
||||
#define VC_CONTAINER_CODEC_ATRACL VC_FOURCC('a','t','r','l')
|
||||
#define VC_CONTAINER_CODEC_MIDI VC_FOURCC('m','i','d','i')
|
||||
#define VC_CONTAINER_CODEC_EVRC VC_FOURCC('e','v','r','c')
|
||||
#define VC_CONTAINER_CODEC_NELLYMOSER VC_FOURCC('n','e','l','y')
|
||||
#define VC_CONTAINER_CODEC_QCELP VC_FOURCC('q','c','e','l')
|
||||
|
||||
/* Text */
|
||||
#define VC_CONTAINER_CODEC_TEXT VC_FOURCC('t','e','x','t')
|
||||
#define VC_CONTAINER_CODEC_SSA VC_FOURCC('s','s','a',' ')
|
||||
#define VC_CONTAINER_CODEC_USF VC_FOURCC('u','s','f',' ')
|
||||
#define VC_CONTAINER_CODEC_VOBSUB VC_FOURCC('v','s','u','b')
|
||||
|
||||
#define VC_CONTAINER_CODEC_UNKNOWN VC_FOURCC('u','n','k','n')
|
||||
|
||||
/* Codec variants */
|
||||
|
||||
/** ISO 14496-10 Annex B byte stream format */
|
||||
#define VC_CONTAINER_VARIANT_H264_DEFAULT 0
|
||||
/** ISO 14496-15 AVC format (used in mp4/mkv and other containers) */
|
||||
#define VC_CONTAINER_VARIANT_H264_AVC1 VC_FOURCC('a','v','c','C')
|
||||
/** Implicitly delineated NAL units without emulation prevention */
|
||||
#define VC_CONTAINER_VARIANT_H264_RAW VC_FOURCC('r','a','w',' ')
|
||||
|
||||
/** MPEG 1/2 Audio - Layer unknown */
|
||||
#define VC_CONTAINER_VARIANT_MPGA_DEFAULT 0
|
||||
/** MPEG 1/2 Audio - Layer 1 */
|
||||
#define VC_CONTAINER_VARIANT_MPGA_L1 VC_FOURCC('l','1',' ',' ')
|
||||
/** MPEG 1/2 Audio - Layer 2 */
|
||||
#define VC_CONTAINER_VARIANT_MPGA_L2 VC_FOURCC('l','2',' ',' ')
|
||||
/** MPEG 1/2 Audio - Layer 3 */
|
||||
#define VC_CONTAINER_VARIANT_MPGA_L3 VC_FOURCC('l','3',' ',' ')
|
||||
|
||||
/** Converts a WaveFormat ID into a VC_CONTAINER_FOURCC_T.
|
||||
*
|
||||
* \param waveformat_id WaveFormat ID to convert
|
||||
* \return a valid VC_CONTAINER_FOURCC_T or VC_CONTAINER_CODEC_UNKNOWN if no mapping was found.
|
||||
*/
|
||||
VC_CONTAINER_FOURCC_T waveformat_to_codec(uint16_t waveformat_id);
|
||||
|
||||
/** Converts a VC_CONTAINER_FOURCC_T into a WaveFormat ID.
|
||||
*
|
||||
* \param codec VC_CONTAINER_FOURCC_T to convert
|
||||
* \return a valid WaveFormat ID of 0 if no mapping was found.
|
||||
*/
|
||||
uint16_t codec_to_waveformat(VC_CONTAINER_FOURCC_T codec);
|
||||
|
||||
/** Tries to convert a generic fourcc into a VC_CONTAINER_FOURCC_T.
|
||||
*
|
||||
* \param fourcc fourcc to convert
|
||||
* \return a valid VC_CONTAINER_FOURCC_T or VC_CONTAINER_CODEC_UNKNOWN if no mapping was found.
|
||||
*/
|
||||
VC_CONTAINER_FOURCC_T fourcc_to_codec(uint32_t fourcc);
|
||||
|
||||
uint32_t codec_to_fourcc(VC_CONTAINER_FOURCC_T codec);
|
||||
|
||||
/** Tries to convert VideoForWindows fourcc into a VC_CONTAINER_FOURCC_T.
|
||||
*
|
||||
* \param fourcc vfw fourcc to convert
|
||||
* \return a valid VC_CONTAINER_FOURCC_T or VC_CONTAINER_CODEC_UNKNOWN if no mapping was found.
|
||||
*/
|
||||
VC_CONTAINER_FOURCC_T vfw_fourcc_to_codec(uint32_t fourcc);
|
||||
|
||||
/** Tries to convert a VC_CONTAINER_FOURCC_T into a VideoForWindows fourcc.
|
||||
*
|
||||
* \param codec VC_CONTAINER_FOURCC_T to convert
|
||||
* \return a valid vfw fourcc or 0 if no mapping was found.
|
||||
*/
|
||||
uint32_t codec_to_vfw_fourcc(VC_CONTAINER_FOURCC_T codec);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* VC_CONTAINERS_CODECS_H */
|
100
gfx/include/userland/containers/containers_types.h
Normal file
100
gfx/include/userland/containers/containers_types.h
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef VC_CONTAINERS_TYPES_H
|
||||
#define VC_CONTAINERS_TYPES_H
|
||||
|
||||
/** \file containers_types.h
|
||||
* Definition of types used by the containers API
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#if defined( __STDC__ ) && defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#elif defined( __GNUC__ )
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#elif defined(_MSC_VER)
|
||||
#include <stdint.h>
|
||||
#if (_MSC_VER < 1700)
|
||||
typedef __int8 int8_t;
|
||||
typedef unsigned __int8 uint8_t;
|
||||
typedef __int16 int16_t;
|
||||
typedef unsigned __int16 uint16_t;
|
||||
typedef __int32 int32_t;
|
||||
typedef unsigned __int32 uint32_t;
|
||||
typedef __int64 int64_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
#endif
|
||||
#define PRIu16 "u"
|
||||
#define PRIu32 "u"
|
||||
#define PRId64 "I64d"
|
||||
#define PRIi64 "I64i"
|
||||
#define PRIo64 "I64o"
|
||||
#define PRIu64 "I64u"
|
||||
#define PRIx64 "I64x"
|
||||
|
||||
#else
|
||||
typedef signed char int8_t;
|
||||
typedef unsigned char uint8_t;
|
||||
typedef signed short int16_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef signed long int32_t;
|
||||
typedef unsigned long uint32_t;
|
||||
typedef signed long long int64_t;
|
||||
typedef unsigned long long uint64_t;
|
||||
#endif
|
||||
|
||||
/* C99 64bits integers */
|
||||
#ifndef INT64_C
|
||||
# define INT64_C(value) value##LL
|
||||
# define UINT64_C(value) value##ULL
|
||||
#endif
|
||||
|
||||
/* C99 boolean */
|
||||
#ifndef __cplusplus
|
||||
#ifndef bool
|
||||
# define bool int
|
||||
#endif
|
||||
#ifndef true
|
||||
# define true 1
|
||||
#endif
|
||||
#ifndef false
|
||||
# define false 0
|
||||
#endif
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/* FIXME: should be different for big endian */
|
||||
#define VC_FOURCC(a,b,c,d) ((a) | (b << 8) | (c << 16) | (d << 24))
|
||||
|
||||
#endif /* VC_CONTAINERS_TYPES_H */
|
637
gfx/include/userland/containers/core/containers.c
Normal file
637
gfx/include/userland/containers/core/containers.c
Normal file
@ -0,0 +1,637 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "containers/core/containers_private.h"
|
||||
#include "containers/core/containers_io.h"
|
||||
#include "containers/core/containers_filters.h"
|
||||
#include "containers/core/containers_loader.h"
|
||||
#include "containers/core/containers_logging.h"
|
||||
#include "containers/core/containers_utils.h"
|
||||
|
||||
#define WRITER_SPACE_SAFETY_MARGIN (10*1024)
|
||||
#define PACKETIZER_BUFFER_SIZE (32*1024)
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_CONTAINER_T *vc_container_open_reader_with_io( struct VC_CONTAINER_IO_T *io,
|
||||
const char *uri, VC_CONTAINER_STATUS_T *p_status,
|
||||
VC_CONTAINER_PROGRESS_REPORT_FUNC_T pfn_progress, void *progress_userdata)
|
||||
{
|
||||
VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
|
||||
VC_CONTAINER_T *p_ctx = 0;
|
||||
const char *extension;
|
||||
|
||||
VC_CONTAINER_PARAM_UNUSED(pfn_progress);
|
||||
VC_CONTAINER_PARAM_UNUSED(progress_userdata);
|
||||
VC_CONTAINER_PARAM_UNUSED(uri);
|
||||
|
||||
/* Sanity check the i/o */
|
||||
if (!io || !io->pf_read || !io->pf_seek)
|
||||
{
|
||||
LOG_ERROR(0, "invalid i/o instance: %p", io);
|
||||
status = VC_CONTAINER_ERROR_INVALID_ARGUMENT;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Allocate our context before trying out the different readers / writers */
|
||||
p_ctx = malloc( sizeof(*p_ctx) + sizeof(*p_ctx->priv) + sizeof(*p_ctx->drm));
|
||||
if(!p_ctx) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
|
||||
memset(p_ctx, 0, sizeof(*p_ctx) + sizeof(*p_ctx->priv) + sizeof(*p_ctx->drm));
|
||||
p_ctx->priv = (VC_CONTAINER_PRIVATE_T *)(p_ctx + 1);
|
||||
p_ctx->priv->verbosity = vc_container_log_get_default_verbosity();
|
||||
p_ctx->drm = (VC_CONTAINER_DRM_T *)(p_ctx->priv + 1);
|
||||
p_ctx->size = io->size;
|
||||
p_ctx->priv->io = io;
|
||||
p_ctx->priv->uri = io->uri_parts;
|
||||
|
||||
/* If the uri has an extension, use it as a hint when loading the container */
|
||||
extension = vc_uri_path_extension(p_ctx->priv->uri);
|
||||
/* If the user has specified a container, then use that instead */
|
||||
vc_uri_find_query(p_ctx->priv->uri, 0, "container", &extension);
|
||||
|
||||
status = vc_container_load_reader(p_ctx, extension);
|
||||
if (status != VC_CONTAINER_SUCCESS)
|
||||
goto error;
|
||||
|
||||
p_ctx->priv->drm_filter = vc_container_filter_open(VC_FOURCC('d','r','m',' '),
|
||||
VC_FOURCC('u','n','k','n'), p_ctx, &status);
|
||||
if (status != VC_CONTAINER_SUCCESS)
|
||||
{
|
||||
/* Some other problem occurred aside from the filter not being appropriate or
|
||||
the stream not needing it. */
|
||||
if (status != VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED) goto error;
|
||||
|
||||
/* Report no DRM and continue as normal */
|
||||
p_ctx->drm = NULL;
|
||||
status = VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
end:
|
||||
if(p_status) *p_status = status;
|
||||
return p_ctx;
|
||||
|
||||
error:
|
||||
if (p_ctx)
|
||||
{
|
||||
p_ctx->priv->io = NULL; /* The i/o doesn't belong to us */
|
||||
vc_container_close(p_ctx);
|
||||
p_ctx = NULL;
|
||||
}
|
||||
goto end;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_CONTAINER_T *vc_container_open_reader( const char *uri, VC_CONTAINER_STATUS_T *p_status,
|
||||
VC_CONTAINER_PROGRESS_REPORT_FUNC_T pfn_progress, void *progress_userdata)
|
||||
{
|
||||
VC_CONTAINER_IO_T *io;
|
||||
VC_CONTAINER_T *ctx;
|
||||
|
||||
/* Start by opening the URI */
|
||||
io = vc_container_io_open( uri, VC_CONTAINER_IO_MODE_READ, p_status );
|
||||
if (!io)
|
||||
return 0;
|
||||
|
||||
ctx = vc_container_open_reader_with_io( io, uri, p_status, pfn_progress, progress_userdata);
|
||||
if (!ctx)
|
||||
vc_container_io_close(io);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_CONTAINER_T *vc_container_open_writer( const char *uri, VC_CONTAINER_STATUS_T *p_status,
|
||||
VC_CONTAINER_PROGRESS_REPORT_FUNC_T pfn_progress, void *progress_userdata)
|
||||
{
|
||||
VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
|
||||
VC_CONTAINER_T *p_ctx = 0;
|
||||
VC_CONTAINER_IO_T *io;
|
||||
const char *extension;
|
||||
VC_CONTAINER_PARAM_UNUSED(pfn_progress);
|
||||
VC_CONTAINER_PARAM_UNUSED(progress_userdata);
|
||||
|
||||
/* Start by opening the URI */
|
||||
io = vc_container_io_open( uri, VC_CONTAINER_IO_MODE_WRITE, &status );
|
||||
if(!io) goto error;
|
||||
|
||||
/* Make sure we have enough space available to start writing */
|
||||
if(io->max_size && io->max_size < WRITER_SPACE_SAFETY_MARGIN)
|
||||
{
|
||||
LOG_DEBUG(p_ctx, "not enough space available to open a writer");
|
||||
status = VC_CONTAINER_ERROR_OUT_OF_RESOURCES;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Allocate our context before trying out the different readers / writers */
|
||||
p_ctx = malloc( sizeof(*p_ctx) + sizeof(*p_ctx->priv));
|
||||
if(!p_ctx) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
|
||||
memset(p_ctx, 0, sizeof(*p_ctx) + sizeof(*p_ctx->priv));
|
||||
p_ctx->priv = (VC_CONTAINER_PRIVATE_T *)(p_ctx + 1);
|
||||
p_ctx->priv->verbosity = vc_container_log_get_default_verbosity();
|
||||
p_ctx->priv->io = io;
|
||||
p_ctx->priv->uri = io->uri_parts;
|
||||
io = NULL; /* io now owned by the context */
|
||||
|
||||
/* If the uri has an extension, use it as a hint when loading the container */
|
||||
extension = vc_uri_path_extension(p_ctx->priv->uri);
|
||||
/* If the user has specified a container, then use that instead */
|
||||
vc_uri_find_query(p_ctx->priv->uri, 0, "container", &extension);
|
||||
|
||||
status = vc_container_load_writer(p_ctx, extension);
|
||||
if(status != VC_CONTAINER_SUCCESS) goto error;
|
||||
|
||||
end:
|
||||
if(p_status) *p_status = status;
|
||||
return p_ctx;
|
||||
|
||||
error:
|
||||
if(io) vc_container_io_close(io);
|
||||
if (p_ctx) vc_container_close(p_ctx);
|
||||
p_ctx = NULL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_CONTAINER_STATUS_T vc_container_close( VC_CONTAINER_T *p_ctx )
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
if(!p_ctx)
|
||||
return VC_CONTAINER_ERROR_INVALID_ARGUMENT;
|
||||
|
||||
for(i = 0; i < p_ctx->tracks_num; i++)
|
||||
if(p_ctx->tracks[i]->priv->packetizer)
|
||||
vc_packetizer_close(p_ctx->tracks[i]->priv->packetizer);
|
||||
if(p_ctx->priv->packetizer_buffer) free(p_ctx->priv->packetizer_buffer);
|
||||
if(p_ctx->priv->drm_filter) vc_container_filter_close(p_ctx->priv->drm_filter);
|
||||
if(p_ctx->priv->pf_close) p_ctx->priv->pf_close(p_ctx);
|
||||
if(p_ctx->priv->io) vc_container_io_close(p_ctx->priv->io);
|
||||
if(p_ctx->priv->module_handle) vc_container_unload(p_ctx);
|
||||
for(i = 0; i < p_ctx->meta_num; i++) free(p_ctx->meta[i]);
|
||||
if(p_ctx->meta_num) free(p_ctx->meta);
|
||||
p_ctx->meta_num = 0;
|
||||
free(p_ctx);
|
||||
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T container_read_packet( VC_CONTAINER_T *p_ctx,
|
||||
VC_CONTAINER_PACKET_T *p_packet, uint32_t flags )
|
||||
{
|
||||
VC_CONTAINER_STATUS_T status;
|
||||
|
||||
while(1)
|
||||
{
|
||||
status = p_ctx->priv->pf_read(p_ctx, p_packet, flags);
|
||||
if(status == VC_CONTAINER_ERROR_CONTINUE)
|
||||
continue;
|
||||
|
||||
if(!p_packet || (flags & VC_CONTAINER_READ_FLAG_SKIP))
|
||||
return status; /* We've just been requested to skip the data */
|
||||
|
||||
if(status != VC_CONTAINER_SUCCESS)
|
||||
return status;
|
||||
|
||||
/* Skip data from out of bounds tracks, disabled tracks or packets that are encrypted
|
||||
and cannot be decrypted */
|
||||
if(p_packet->track >= p_ctx->tracks_num ||
|
||||
!p_ctx->tracks[p_packet->track]->is_enabled ||
|
||||
((p_packet->flags & VC_CONTAINER_PACKET_FLAG_ENCRYPTED) && !p_ctx->priv->drm_filter))
|
||||
{
|
||||
if(flags & VC_CONTAINER_READ_FLAG_INFO)
|
||||
status = p_ctx->priv->pf_read(p_ctx, p_packet, VC_CONTAINER_READ_FLAG_SKIP);
|
||||
if(status == VC_CONTAINER_SUCCESS || status == VC_CONTAINER_ERROR_CONTINUE)
|
||||
continue;
|
||||
}
|
||||
if(status != VC_CONTAINER_SUCCESS)
|
||||
return status;
|
||||
|
||||
if(p_ctx->priv->drm_filter)
|
||||
status = vc_container_filter_process(p_ctx->priv->drm_filter, p_packet);
|
||||
|
||||
break;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_CONTAINER_STATUS_T vc_container_read( VC_CONTAINER_T *p_ctx, VC_CONTAINER_PACKET_T *p_packet, uint32_t flags )
|
||||
{
|
||||
VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_CONTINUE;
|
||||
VC_PACKETIZER_FLAGS_T packetizer_flags = 0;
|
||||
VC_PACKETIZER_T *packetizer;
|
||||
uint32_t force = flags & VC_CONTAINER_READ_FLAG_FORCE_TRACK;
|
||||
unsigned int i;
|
||||
|
||||
if(!p_packet && !(flags & VC_CONTAINER_READ_FLAG_SKIP))
|
||||
return VC_CONTAINER_ERROR_INVALID_ARGUMENT;
|
||||
if(!p_packet && (flags & VC_CONTAINER_READ_FLAG_INFO))
|
||||
return VC_CONTAINER_ERROR_INVALID_ARGUMENT;
|
||||
if(p_packet && !p_packet->data && !(flags & (VC_CONTAINER_READ_FLAG_INFO | VC_CONTAINER_READ_FLAG_SKIP)))
|
||||
return VC_CONTAINER_ERROR_INVALID_ARGUMENT;
|
||||
if((flags & VC_CONTAINER_READ_FLAG_FORCE_TRACK) &&
|
||||
(!p_packet || p_packet->track >= p_ctx->tracks_num || !p_ctx->tracks[p_packet->track]->is_enabled))
|
||||
return VC_CONTAINER_ERROR_INVALID_ARGUMENT;
|
||||
|
||||
/* Always having a packet structure to work with simplifies things */
|
||||
if(!p_packet)
|
||||
p_packet = &p_ctx->priv->packetizer_packet;
|
||||
|
||||
/* Simple/Fast case first */
|
||||
if(!p_ctx->priv->packetizing)
|
||||
{
|
||||
status = container_read_packet( p_ctx, p_packet, flags );
|
||||
goto end;
|
||||
}
|
||||
|
||||
if(flags & VC_CONTAINER_READ_FLAG_INFO)
|
||||
packetizer_flags |= VC_PACKETIZER_FLAG_INFO;
|
||||
if(flags & VC_CONTAINER_READ_FLAG_SKIP)
|
||||
packetizer_flags |= VC_PACKETIZER_FLAG_SKIP;
|
||||
|
||||
/* Loop through all the packetized tracks first to see if we've got any
|
||||
* data to consume there */
|
||||
for(i = 0; i < p_ctx->tracks_num; i++)
|
||||
{
|
||||
VC_PACKETIZER_T *packetizer = p_ctx->tracks[i]->priv->packetizer;
|
||||
if(!p_ctx->tracks[i]->is_enabled || !packetizer ||
|
||||
(force && i != p_packet->track))
|
||||
continue;
|
||||
|
||||
status = vc_packetizer_read(packetizer, p_packet, packetizer_flags);
|
||||
p_packet->track = i;
|
||||
if(status == VC_CONTAINER_SUCCESS)
|
||||
break;
|
||||
}
|
||||
if(i < p_ctx->tracks_num) /* We've got some data */
|
||||
goto end;
|
||||
|
||||
/* Let's go and read some data from the actual container */
|
||||
while(1)
|
||||
{
|
||||
VC_CONTAINER_PACKET_T *tmp = &p_ctx->priv->packetizer_packet;
|
||||
tmp->track = p_packet->track;
|
||||
|
||||
/* Let's check what the container has to offer */
|
||||
status = container_read_packet( p_ctx, tmp, force|VC_PACKETIZER_FLAG_INFO );
|
||||
if(status != VC_CONTAINER_SUCCESS)
|
||||
return status;
|
||||
|
||||
if(!p_ctx->tracks[tmp->track]->priv->packetizer)
|
||||
{
|
||||
status = container_read_packet( p_ctx, p_packet, flags );
|
||||
break;
|
||||
}
|
||||
|
||||
/* Feed data from the container onto the packetizer */
|
||||
packetizer = p_ctx->tracks[tmp->track]->priv->packetizer;
|
||||
|
||||
tmp->data = p_ctx->priv->packetizer_buffer;
|
||||
tmp->buffer_size = PACKETIZER_BUFFER_SIZE;
|
||||
tmp->size = 0;
|
||||
status = container_read_packet( p_ctx, tmp, force );
|
||||
if(status != VC_CONTAINER_SUCCESS)
|
||||
return status;
|
||||
|
||||
p_packet->track = tmp->track;
|
||||
vc_packetizer_push(packetizer, tmp);
|
||||
vc_packetizer_pop(packetizer, &tmp, VC_PACKETIZER_FLAG_FORCE_RELEASE_INPUT);
|
||||
|
||||
status = vc_packetizer_read(packetizer, p_packet, packetizer_flags);
|
||||
if(status == VC_CONTAINER_SUCCESS)
|
||||
break;
|
||||
}
|
||||
|
||||
end:
|
||||
if(status != VC_CONTAINER_SUCCESS)
|
||||
return status;
|
||||
|
||||
if(p_packet && p_packet->dts > p_ctx->position)
|
||||
p_ctx->position = p_packet->dts;
|
||||
if(p_packet && p_packet->pts > p_ctx->position)
|
||||
p_ctx->position = p_packet->pts;
|
||||
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_CONTAINER_STATUS_T vc_container_write( VC_CONTAINER_T *p_ctx, VC_CONTAINER_PACKET_T *p_packet )
|
||||
{
|
||||
VC_CONTAINER_STATUS_T status;
|
||||
void * p_metadata_buffer = NULL;
|
||||
uint32_t metadata_length = 0;
|
||||
|
||||
/* TODO: check other similar argument errors and non-stateless errors */
|
||||
if (!p_packet || !p_packet->data || p_packet->track >= p_ctx->tracks_num)
|
||||
return VC_CONTAINER_ERROR_INVALID_ARGUMENT;
|
||||
|
||||
/* Check for a previous error */
|
||||
if(p_ctx->priv->status != VC_CONTAINER_SUCCESS && p_ctx->priv->status != VC_CONTAINER_ERROR_NOT_READY)
|
||||
return p_ctx->priv->status;
|
||||
|
||||
/* Check we have enough space to write the data */
|
||||
if(p_ctx->priv->max_size &&
|
||||
p_ctx->size + p_packet->size + WRITER_SPACE_SAFETY_MARGIN > p_ctx->priv->max_size)
|
||||
{status = VC_CONTAINER_ERROR_LIMIT_REACHED; goto end;}
|
||||
if(p_ctx->priv->io->max_size &&
|
||||
p_ctx->size + p_packet->size + WRITER_SPACE_SAFETY_MARGIN +
|
||||
(p_ctx->priv->tmp_io ? p_ctx->priv->tmp_io->offset : 0) > p_ctx->priv->io->max_size)
|
||||
{status = VC_CONTAINER_ERROR_OUT_OF_SPACE; goto end;}
|
||||
|
||||
/* If a filter is created, then send the packet to the filter for encryption. */
|
||||
if(p_ctx->priv->drm_filter)
|
||||
{
|
||||
status = vc_container_filter_process(p_ctx->priv->drm_filter, p_packet);
|
||||
|
||||
if(status == VC_CONTAINER_SUCCESS)
|
||||
{
|
||||
/* Get the encryption metadata and send it to the output first. */
|
||||
if(vc_container_control(p_ctx, VC_CONTAINER_CONTROL_GET_DRM_METADATA,
|
||||
&p_metadata_buffer, &metadata_length) == VC_CONTAINER_SUCCESS && metadata_length > 0)
|
||||
{
|
||||
/* Make a packet up with the metadata in the payload and write it. */
|
||||
VC_CONTAINER_PACKET_T metadata_packet;
|
||||
metadata_packet.data = p_metadata_buffer;
|
||||
metadata_packet.buffer_size = metadata_length;
|
||||
metadata_packet.size = metadata_length;
|
||||
metadata_packet.frame_size = p_packet->frame_size + metadata_length;
|
||||
metadata_packet.pts = p_packet->pts;
|
||||
metadata_packet.dts = p_packet->dts;
|
||||
metadata_packet.num = p_packet->num;
|
||||
metadata_packet.track = p_packet->track;
|
||||
/* As this packet is written first, we must transfer any frame start
|
||||
flag from the following packet. Also, this packet can never have the end flag set. */
|
||||
metadata_packet.flags = p_packet->flags & ~VC_CONTAINER_PACKET_FLAG_FRAME_END;
|
||||
|
||||
p_packet->pts = p_packet->dts = VC_CONTAINER_TIME_UNKNOWN;
|
||||
p_packet->flags &= ~VC_CONTAINER_PACKET_FLAG_FRAME_START;
|
||||
if(p_ctx->priv->pf_write(p_ctx, &metadata_packet) != VC_CONTAINER_SUCCESS) goto end;
|
||||
}
|
||||
}
|
||||
else if (status != VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION)
|
||||
{
|
||||
/* Encryption was appropriate but a problem has occurred. Skip the write of data
|
||||
to the io and return the status to the caller. */
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
status = p_ctx->priv->pf_write(p_ctx, p_packet);
|
||||
|
||||
end:
|
||||
p_ctx->priv->status = status;
|
||||
return status;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_CONTAINER_STATUS_T vc_container_seek( VC_CONTAINER_T *p_ctx, int64_t *p_offset,
|
||||
VC_CONTAINER_SEEK_MODE_T mode, VC_CONTAINER_SEEK_FLAGS_T flags)
|
||||
{
|
||||
VC_CONTAINER_STATUS_T status;
|
||||
int64_t offset = *p_offset;
|
||||
unsigned int i;
|
||||
|
||||
/* Reset all packetizers */
|
||||
for(i = 0; i < p_ctx->tracks_num; i++)
|
||||
if(p_ctx->tracks[i]->priv->packetizer)
|
||||
vc_packetizer_reset(p_ctx->tracks[i]->priv->packetizer);
|
||||
|
||||
status = p_ctx->priv->pf_seek(p_ctx, p_offset, mode, flags);
|
||||
|
||||
/* */
|
||||
if(status == VC_CONTAINER_SUCCESS && (flags & VC_CONTAINER_SEEK_FLAG_FORWARD) &&
|
||||
*p_offset < offset)
|
||||
{
|
||||
LOG_DEBUG(p_ctx, "container didn't seek forward as requested (%"PRIi64"/%"PRIi64")",
|
||||
*p_offset, offset);
|
||||
for(i = 1; i <= 5 && *p_offset < offset; i++)
|
||||
{
|
||||
*p_offset = offset + i * i * 100000;
|
||||
status = p_ctx->priv->pf_seek(p_ctx, p_offset, mode, flags);
|
||||
if(status != VC_CONTAINER_SUCCESS) break;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_CONTAINER_STATUS_T vc_container_control( VC_CONTAINER_T *p_ctx, VC_CONTAINER_CONTROL_T operation, ... )
|
||||
{
|
||||
VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
|
||||
va_list args;
|
||||
|
||||
va_start( args, operation );
|
||||
|
||||
if(operation == VC_CONTAINER_CONTROL_ENCRYPT_TRACK)
|
||||
{
|
||||
VC_CONTAINER_FOURCC_T type = va_arg(args, VC_CONTAINER_FOURCC_T);
|
||||
|
||||
uint32_t track_num = va_arg(args, uint32_t);
|
||||
void *p_drm_data = va_arg(args, void *);
|
||||
int drm_data_size = va_arg(args, uint32_t);
|
||||
|
||||
if(!p_ctx->priv->drm_filter && track_num < p_ctx->tracks_num)
|
||||
{
|
||||
VC_CONTAINER_TRACK_T * p_track = p_ctx->tracks[track_num];
|
||||
|
||||
if ((status = vc_container_track_allocate_drmdata(p_ctx, p_track, drm_data_size)) != VC_CONTAINER_SUCCESS)
|
||||
{
|
||||
LOG_DEBUG(p_ctx, "failed to allocate memory for 'drm data' (%d bytes)", drm_data_size);
|
||||
goto end;
|
||||
}
|
||||
memcpy(p_track->priv->drmdata, p_drm_data, drm_data_size);
|
||||
|
||||
/* Track encryption enabled and no filter - create one now. */
|
||||
p_ctx->priv->drm_filter = vc_container_filter_open(VC_FOURCC('d','r','m',' '), type, p_ctx, &status);
|
||||
if(status != VC_CONTAINER_SUCCESS)
|
||||
goto end;
|
||||
|
||||
status = vc_container_filter_control(p_ctx->priv->drm_filter, operation, track_num);
|
||||
}
|
||||
}
|
||||
else if(operation == VC_CONTAINER_CONTROL_GET_DRM_METADATA)
|
||||
{
|
||||
void *p_drm_data = va_arg(args, void *);
|
||||
int *drm_data_size = va_arg(args, int *);
|
||||
status = vc_container_filter_control(p_ctx->priv->drm_filter, operation, p_drm_data, drm_data_size);
|
||||
}
|
||||
|
||||
if(status == VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION && p_ctx->priv->pf_control)
|
||||
status = p_ctx->priv->pf_control(p_ctx, operation, args);
|
||||
|
||||
/* If the request has already been handled then we're done */
|
||||
if(status != VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION)
|
||||
goto end;
|
||||
|
||||
switch(operation)
|
||||
{
|
||||
case VC_CONTAINER_CONTROL_DRM_PLAY:
|
||||
if (p_ctx->priv->drm_filter)
|
||||
status = vc_container_filter_control(p_ctx->priv->drm_filter, operation, args);
|
||||
break;
|
||||
|
||||
case VC_CONTAINER_CONTROL_SET_MAXIMUM_SIZE:
|
||||
p_ctx->priv->max_size = (uint64_t)va_arg( args, uint64_t );
|
||||
if(p_ctx->priv->io->max_size &&
|
||||
p_ctx->priv->max_size > p_ctx->priv->io->max_size)
|
||||
p_ctx->priv->max_size = p_ctx->priv->io->max_size;
|
||||
status = VC_CONTAINER_SUCCESS;
|
||||
break;
|
||||
|
||||
case VC_CONTAINER_CONTROL_TRACK_PACKETIZE:
|
||||
{
|
||||
unsigned int track_num = va_arg(args, unsigned int);
|
||||
VC_CONTAINER_FOURCC_T fourcc = va_arg(args, VC_CONTAINER_FOURCC_T);
|
||||
VC_CONTAINER_TRACK_T *p_track;
|
||||
|
||||
if(track_num >= p_ctx->tracks_num)
|
||||
{
|
||||
status = VC_CONTAINER_ERROR_INVALID_ARGUMENT;
|
||||
break;
|
||||
}
|
||||
if(p_ctx->tracks[track_num]->priv->packetizer)
|
||||
{
|
||||
status = VC_CONTAINER_SUCCESS;
|
||||
break;
|
||||
}
|
||||
|
||||
p_track = p_ctx->tracks[track_num];
|
||||
p_track->priv->packetizer = vc_packetizer_open( p_track->format, fourcc, &status );
|
||||
if(!p_track->priv->packetizer)
|
||||
break;
|
||||
|
||||
if(!p_ctx->priv->packetizer_buffer)
|
||||
{
|
||||
p_ctx->priv->packetizer_buffer = malloc(PACKETIZER_BUFFER_SIZE);
|
||||
if(!p_ctx->priv->packetizer_buffer)
|
||||
{
|
||||
status = VC_CONTAINER_ERROR_OUT_OF_MEMORY;
|
||||
vc_packetizer_close(p_track->priv->packetizer);
|
||||
p_track->priv->packetizer = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
vc_container_format_copy(p_track->format, p_track->priv->packetizer->out,
|
||||
p_track->format->extradata_size);
|
||||
p_track->format->flags |= VC_CONTAINER_ES_FORMAT_FLAG_FRAMED;
|
||||
p_ctx->priv->packetizing = true;
|
||||
}
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
if (status == VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION)
|
||||
status = vc_container_io_control_list(p_ctx->priv->io, operation, args);
|
||||
|
||||
end:
|
||||
va_end( args );
|
||||
return status;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_CONTAINER_TRACK_T *vc_container_allocate_track( VC_CONTAINER_T *context, unsigned int extra_size )
|
||||
{
|
||||
VC_CONTAINER_TRACK_T *p_ctx;
|
||||
unsigned int size;
|
||||
VC_CONTAINER_PARAM_UNUSED(context);
|
||||
|
||||
size = sizeof(*p_ctx) + sizeof(*p_ctx->priv) + sizeof(*p_ctx->format) +
|
||||
sizeof(*p_ctx->format->type) + extra_size;
|
||||
|
||||
p_ctx = malloc(size);
|
||||
if(!p_ctx) return 0;
|
||||
|
||||
memset(p_ctx, 0, size);
|
||||
p_ctx->priv = (VC_CONTAINER_TRACK_PRIVATE_T *)(p_ctx + 1);
|
||||
p_ctx->format = (VC_CONTAINER_ES_FORMAT_T *)(p_ctx->priv + 1);
|
||||
p_ctx->format->type = (void *)(p_ctx->format + 1);
|
||||
p_ctx->priv->module = (struct VC_CONTAINER_TRACK_MODULE_T *)(p_ctx->format->type + 1);
|
||||
return p_ctx;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
void vc_container_free_track( VC_CONTAINER_T *context, VC_CONTAINER_TRACK_T *p_track )
|
||||
{
|
||||
VC_CONTAINER_PARAM_UNUSED(context);
|
||||
if(p_track)
|
||||
{
|
||||
if(p_track->priv->extradata) free(p_track->priv->extradata);
|
||||
if(p_track->priv->drmdata) free(p_track->priv->drmdata);
|
||||
free(p_track);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_CONTAINER_STATUS_T vc_container_track_allocate_extradata( VC_CONTAINER_T *context,
|
||||
VC_CONTAINER_TRACK_T *p_track, unsigned int extra_size )
|
||||
{
|
||||
VC_CONTAINER_PARAM_UNUSED(context);
|
||||
|
||||
/* Sanity check the size of the extra data */
|
||||
if(extra_size > 100*1024) return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
|
||||
|
||||
/* Check if we need to allocate a buffer */
|
||||
if(extra_size > p_track->priv->extradata_size)
|
||||
{
|
||||
p_track->priv->extradata_size = 0;
|
||||
if(p_track->priv->extradata) free(p_track->priv->extradata);
|
||||
p_track->priv->extradata = malloc(extra_size);
|
||||
p_track->format->extradata = p_track->priv->extradata;
|
||||
if(!p_track->priv->extradata) return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
|
||||
p_track->priv->extradata_size = extra_size;
|
||||
}
|
||||
p_track->format->extradata = p_track->priv->extradata;
|
||||
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_CONTAINER_STATUS_T vc_container_track_allocate_drmdata( VC_CONTAINER_T *context,
|
||||
VC_CONTAINER_TRACK_T *p_track, unsigned int size )
|
||||
{
|
||||
VC_CONTAINER_PARAM_UNUSED(context);
|
||||
|
||||
/* Sanity check the size of the drm data */
|
||||
if(size > 200*1024) return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
|
||||
|
||||
/* Check if we need to allocate a buffer */
|
||||
if(size > p_track->priv->drmdata_size)
|
||||
{
|
||||
p_track->priv->drmdata_size = 0;
|
||||
if(p_track->priv->drmdata) free(p_track->priv->drmdata);
|
||||
p_track->priv->drmdata = malloc(size);
|
||||
if(!p_track->priv->drmdata) return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
|
||||
p_track->priv->drmdata_size = size;
|
||||
}
|
||||
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
490
gfx/include/userland/containers/core/containers_bits.c
Normal file
490
gfx/include/userland/containers/core/containers_bits.c
Normal file
@ -0,0 +1,490 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "containers/core/containers_bits.h"
|
||||
#include "containers/core/containers_common.h"
|
||||
|
||||
#ifdef ENABLE_CONTAINERS_LOG_FORMAT
|
||||
#include "containers/core/containers_logging.h"
|
||||
#endif
|
||||
|
||||
/******************************************************************************
|
||||
Defines and constants.
|
||||
******************************************************************************/
|
||||
|
||||
#ifdef ENABLE_CONTAINERS_LOG_FORMAT
|
||||
/** String used for indentation. If more spaces are needed, just add them. */
|
||||
#define INDENT_SPACES_STRING "> "
|
||||
#define INDENT_SPACES_LENGTH (sizeof(INDENT_SPACES_STRING) - 1)
|
||||
#endif /* ENABLE_CONTAINERS_LOG_FORMAT */
|
||||
|
||||
/******************************************************************************
|
||||
Type definitions
|
||||
******************************************************************************/
|
||||
|
||||
/******************************************************************************
|
||||
Function prototypes
|
||||
******************************************************************************/
|
||||
|
||||
/******************************************************************************
|
||||
Local Functions
|
||||
******************************************************************************/
|
||||
|
||||
#ifdef ENABLE_CONTAINERS_LOG_FORMAT
|
||||
|
||||
/**************************************************************************//**
|
||||
* Returns a string that indicates whether the bit stream is valid or not.
|
||||
*
|
||||
* \pre bit_stream is not NULL.
|
||||
*
|
||||
* \param bit_stream The bit stream object.
|
||||
* \return A string indicating the validity of the stream.
|
||||
*/
|
||||
static const char * vc_container_bits_valid_str( VC_CONTAINER_BITS_T *bit_stream )
|
||||
{
|
||||
return vc_container_bits_valid(bit_stream) ? "" : " - stream invalid";
|
||||
}
|
||||
|
||||
/**************************************************************************//**
|
||||
* Returns a string of spaces the length of which is determined by the
|
||||
* parameter.
|
||||
* The length is limited to a certain size, above which a greater than symbol
|
||||
* prefixes the maximum number of spaces.
|
||||
*
|
||||
* \param length The required length of the string.
|
||||
* \return A string indicating the validity of the stream.
|
||||
*/
|
||||
static const char * vc_container_bits_indent_str(uint32_t length)
|
||||
{
|
||||
uint32_t str_length = length;
|
||||
|
||||
if (str_length > INDENT_SPACES_LENGTH)
|
||||
str_length = INDENT_SPACES_LENGTH;
|
||||
|
||||
return INDENT_SPACES_STRING + (INDENT_SPACES_LENGTH - str_length);
|
||||
}
|
||||
|
||||
#endif /* ENABLE_CONTAINERS_LOG_FORMAT */
|
||||
|
||||
/**************************************************************************//**
|
||||
* Returns the number of consecutive zero bits in the stream.
|
||||
* the zero bits are terminated either by a one bit, or the end of the stream.
|
||||
* In the former case, the zero bits and the terminating one bit are removed
|
||||
* from the stream.
|
||||
* In the latter case, the stream becomes invalid. The stream also becomes
|
||||
* invalid if there are not as many bits after the one bit as zero bits before
|
||||
* it.
|
||||
* If the stream is already or becomes invalid, zero is returned.
|
||||
*
|
||||
* \pre bit_stream is not NULL.
|
||||
*
|
||||
* \param bit_stream The bit stream object.
|
||||
* \return The number of consecutive zero bits, or zero if the stream is
|
||||
* invalid.
|
||||
*/
|
||||
static uint32_t vc_container_bits_get_leading_zero_bits( VC_CONTAINER_BITS_T *bit_stream )
|
||||
{
|
||||
uint32_t leading_zero_bits;
|
||||
uint32_t bits_left = vc_container_bits_available(bit_stream);
|
||||
uint32_t bits;
|
||||
uint8_t mask, current_byte;
|
||||
|
||||
if (!bits_left)
|
||||
return vc_container_bits_invalidate(bit_stream);
|
||||
|
||||
/* Cache 'bits' field to avoid repeated pointer access */
|
||||
bits = bit_stream->bits;
|
||||
if (bits)
|
||||
{
|
||||
current_byte = *bit_stream->buffer;
|
||||
mask = 1 << (bits - 1);
|
||||
} else {
|
||||
/* Initialize variables to placate the compiler */
|
||||
current_byte = 0;
|
||||
mask = 0;
|
||||
}
|
||||
|
||||
/* Scan for the first one bit, counting the number of zeroes. This gives the
|
||||
* number of further bits after the one that are part of the value. See
|
||||
* section 9.1 of ITU-T REC H.264 201003 for more details. */
|
||||
|
||||
for (leading_zero_bits = 0; leading_zero_bits < bits_left; leading_zero_bits++)
|
||||
{
|
||||
if (!bits)
|
||||
{
|
||||
if (!bit_stream->bytes)
|
||||
return vc_container_bits_invalidate(bit_stream);
|
||||
bit_stream->bytes--;
|
||||
current_byte = *(++bit_stream->buffer);
|
||||
bits = 8;
|
||||
mask = 0x80;
|
||||
}
|
||||
|
||||
bits--;
|
||||
bits_left--;
|
||||
if (current_byte & mask)
|
||||
break; /* Found the marker bit */
|
||||
|
||||
mask >>= 1;
|
||||
}
|
||||
|
||||
/* Check enough bits are left in the stream for the value. */
|
||||
if (leading_zero_bits > bits_left)
|
||||
return vc_container_bits_invalidate(bit_stream);
|
||||
|
||||
/* Return cached value of bits to the stream */
|
||||
bit_stream->bits = bits;
|
||||
|
||||
return leading_zero_bits;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
Functions exported as part of the bit stream API
|
||||
*****************************************************************************/
|
||||
|
||||
/*****************************************************************************/
|
||||
void vc_container_bits_init(VC_CONTAINER_BITS_T *bit_stream,
|
||||
const uint8_t *buffer,
|
||||
uint32_t available)
|
||||
{
|
||||
vc_container_assert(buffer && (buffer != (const uint8_t *)1));
|
||||
|
||||
/* Start with buffer pointing at the previous byte with no bits available
|
||||
* to make the mathematics easier */
|
||||
bit_stream->buffer = buffer - 1;
|
||||
bit_stream->bytes = available;
|
||||
bit_stream->bits = 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
uint32_t vc_container_bits_invalidate( VC_CONTAINER_BITS_T *bit_stream )
|
||||
{
|
||||
bit_stream->buffer = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
bool vc_container_bits_valid(VC_CONTAINER_BITS_T *bit_stream)
|
||||
{
|
||||
return (bit_stream->buffer != NULL);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
void vc_container_bits_reset(VC_CONTAINER_BITS_T *bit_stream)
|
||||
{
|
||||
bit_stream->bytes = 0;
|
||||
bit_stream->bits = 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
const uint8_t *vc_container_bits_current_pointer(const VC_CONTAINER_BITS_T *bit_stream)
|
||||
{
|
||||
const uint8_t *buffer = bit_stream->buffer;
|
||||
|
||||
/* Only valid on byte boundaries, where buffer pointer has not been moved yet */
|
||||
vc_container_assert(!bit_stream->bits);
|
||||
|
||||
return buffer ? (buffer + 1) : NULL;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
void vc_container_bits_copy_stream(VC_CONTAINER_BITS_T *dst,
|
||||
const VC_CONTAINER_BITS_T *src)
|
||||
{
|
||||
memcpy(dst, src, sizeof(VC_CONTAINER_BITS_T));
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
uint32_t vc_container_bits_available(const VC_CONTAINER_BITS_T *bit_stream)
|
||||
{
|
||||
if (!bit_stream->buffer)
|
||||
return 0;
|
||||
return (bit_stream->bytes << 3) + bit_stream->bits;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
uint32_t vc_container_bits_bytes_available(const VC_CONTAINER_BITS_T *bit_stream)
|
||||
{
|
||||
if (!bit_stream->buffer)
|
||||
return 0;
|
||||
|
||||
vc_container_assert(!bit_stream->bits);
|
||||
|
||||
return vc_container_bits_available(bit_stream) >> 3;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
void vc_container_bits_skip(VC_CONTAINER_BITS_T *bit_stream,
|
||||
uint32_t bits_to_skip)
|
||||
{
|
||||
uint32_t have_bits;
|
||||
uint32_t new_bytes;
|
||||
|
||||
have_bits = vc_container_bits_available(bit_stream);
|
||||
if (have_bits < bits_to_skip)
|
||||
{
|
||||
vc_container_bits_invalidate(bit_stream);
|
||||
return;
|
||||
}
|
||||
|
||||
have_bits -= bits_to_skip;
|
||||
new_bytes = have_bits >> 3;
|
||||
bit_stream->bits = have_bits & 7;
|
||||
bit_stream->buffer += (bit_stream->bytes - new_bytes);
|
||||
bit_stream->bytes = new_bytes;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
void vc_container_bits_skip_bytes(VC_CONTAINER_BITS_T *bit_stream,
|
||||
uint32_t bytes_to_skip)
|
||||
{
|
||||
/* Only valid on byte boundaries */
|
||||
vc_container_assert(!bit_stream->bits);
|
||||
|
||||
vc_container_bits_skip(bit_stream, bytes_to_skip << 3);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
void vc_container_bits_reduce_bytes(VC_CONTAINER_BITS_T *bit_stream,
|
||||
uint32_t bytes_to_reduce)
|
||||
{
|
||||
if (bit_stream->bytes >= bytes_to_reduce)
|
||||
bit_stream->bytes -= bytes_to_reduce;
|
||||
else
|
||||
vc_container_bits_invalidate(bit_stream);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
void vc_container_bits_copy_bytes(VC_CONTAINER_BITS_T *bit_stream,
|
||||
uint32_t bytes_to_copy,
|
||||
uint8_t *dst)
|
||||
{
|
||||
vc_container_assert(!bit_stream->bits);
|
||||
|
||||
if (bit_stream->bytes < bytes_to_copy)
|
||||
{
|
||||
/* Not enough data */
|
||||
vc_container_bits_invalidate(bit_stream);
|
||||
return;
|
||||
}
|
||||
|
||||
/* When the number of bits is zero, the next byte to take is at buffer + 1 */
|
||||
memcpy(dst, bit_stream->buffer + 1, bytes_to_copy);
|
||||
bit_stream->buffer += bytes_to_copy;
|
||||
bit_stream->bytes -= bytes_to_copy;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
uint32_t vc_container_bits_read_u32(VC_CONTAINER_BITS_T *bit_stream,
|
||||
uint32_t value_bits)
|
||||
{
|
||||
uint32_t value = 0;
|
||||
uint32_t needed = value_bits;
|
||||
uint32_t bits;
|
||||
|
||||
vc_container_assert(value_bits <= 32);
|
||||
|
||||
if (needed > vc_container_bits_available(bit_stream))
|
||||
return vc_container_bits_invalidate(bit_stream);
|
||||
|
||||
bits = bit_stream->bits;
|
||||
while (needed)
|
||||
{
|
||||
uint32_t take;
|
||||
|
||||
if (!bits)
|
||||
{
|
||||
bit_stream->bytes--;
|
||||
bit_stream->buffer++;
|
||||
bits = 8;
|
||||
}
|
||||
|
||||
take = bits;
|
||||
if (needed < take) take = needed;
|
||||
|
||||
bits -= take;
|
||||
needed -= take;
|
||||
|
||||
value <<= take;
|
||||
if (take == 8)
|
||||
value |= *bit_stream->buffer; /* optimize whole byte case */
|
||||
else
|
||||
value |= (*bit_stream->buffer >> bits) & ((1 << take) - 1);
|
||||
}
|
||||
|
||||
bit_stream->bits = bits;
|
||||
return value;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
void vc_container_bits_skip_exp_golomb(VC_CONTAINER_BITS_T *bit_stream)
|
||||
{
|
||||
vc_container_bits_skip(bit_stream, vc_container_bits_get_leading_zero_bits(bit_stream));
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
uint32_t vc_container_bits_read_u32_exp_golomb(VC_CONTAINER_BITS_T *bit_stream)
|
||||
{
|
||||
uint32_t leading_zero_bits;
|
||||
uint32_t codeNum;
|
||||
|
||||
leading_zero_bits = vc_container_bits_get_leading_zero_bits(bit_stream);
|
||||
|
||||
/* Anything bigger than 32 bits is definitely overflow */
|
||||
if (leading_zero_bits > 32)
|
||||
return vc_container_bits_invalidate(bit_stream);
|
||||
|
||||
codeNum = vc_container_bits_read_u32(bit_stream, leading_zero_bits);
|
||||
|
||||
if (leading_zero_bits == 32)
|
||||
{
|
||||
/* If codeNum is non-zero, it would need 33 bits, so is also overflow */
|
||||
if (codeNum)
|
||||
return vc_container_bits_invalidate(bit_stream);
|
||||
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
return codeNum + (1 << leading_zero_bits) - 1;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int32_t vc_container_bits_read_s32_exp_golomb(VC_CONTAINER_BITS_T *bit_stream)
|
||||
{
|
||||
uint32_t uval;
|
||||
|
||||
uval = vc_container_bits_read_u32_exp_golomb(bit_stream);
|
||||
|
||||
/* The signed Exp-Golomb code 0xFFFFFFFF cannot be represented as a signed 32-bit
|
||||
* integer, because it should be one larger than the largest positive value. */
|
||||
if (uval == 0xFFFFFFFF)
|
||||
return vc_container_bits_invalidate(bit_stream);
|
||||
|
||||
/* Definition of conversion is
|
||||
* s = ((-1)^(u + 1)) * Ceil(u / 2)
|
||||
* where '^' is power, but this should be equivalent */
|
||||
return ((int32_t)((uval & 1) << 1) - 1) * (int32_t)((uval >> 1) + (uval & 1));
|
||||
}
|
||||
|
||||
#ifdef ENABLE_CONTAINERS_LOG_FORMAT
|
||||
|
||||
/*****************************************************************************/
|
||||
void vc_container_bits_log(VC_CONTAINER_T *p_ctx,
|
||||
uint32_t indent,
|
||||
const char *txt,
|
||||
VC_CONTAINER_BITS_T *bit_stream,
|
||||
VC_CONTAINER_BITS_LOG_OP_T op,
|
||||
uint32_t length)
|
||||
{
|
||||
const char *valid_str = vc_container_bits_valid_str(bit_stream);
|
||||
const char *indent_str = vc_container_bits_indent_str(indent);
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case VC_CONTAINER_BITS_LOG_SKIP:
|
||||
vc_container_log(p_ctx, VC_CONTAINER_LOG_FORMAT, "%s%s: %u bits skipped%s", indent_str, txt, length, valid_str);
|
||||
break;
|
||||
case VC_CONTAINER_BITS_LOG_SKIP_BYTES:
|
||||
vc_container_log(p_ctx, VC_CONTAINER_LOG_FORMAT, "%s%s: %u bytes skipped%s", indent_str, txt, length, valid_str);
|
||||
break;
|
||||
case VC_CONTAINER_BITS_LOG_COPY_BYTES:
|
||||
vc_container_log(p_ctx, VC_CONTAINER_LOG_FORMAT, "%s%s: %u bytes copied%s", indent_str, txt, length, valid_str);
|
||||
break;
|
||||
case VC_CONTAINER_BITS_LOG_REDUCE_BYTES:
|
||||
vc_container_log(p_ctx, VC_CONTAINER_LOG_FORMAT, "%s%s: %u bytes reduced%s", indent_str, txt, length, valid_str);
|
||||
break;
|
||||
case VC_CONTAINER_BITS_LOG_EG_SKIP:
|
||||
vc_container_log(p_ctx, VC_CONTAINER_LOG_FORMAT, "%s%s: Exp-Golomb value skipped%s", indent_str, txt, valid_str);
|
||||
break;
|
||||
default:
|
||||
/* Unexpected operation. Check bit stream logging macros */
|
||||
vc_container_assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
uint32_t vc_container_bits_log_u32(VC_CONTAINER_T *p_ctx,
|
||||
uint32_t indent,
|
||||
const char *txt,
|
||||
VC_CONTAINER_BITS_T *bit_stream,
|
||||
VC_CONTAINER_BITS_LOG_OP_T op,
|
||||
uint32_t length,
|
||||
uint32_t value)
|
||||
{
|
||||
const char *valid_str = vc_container_bits_valid_str(bit_stream);
|
||||
const char *indent_str = vc_container_bits_indent_str(indent);
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case VC_CONTAINER_BITS_LOG_U8:
|
||||
vc_container_log(p_ctx, VC_CONTAINER_LOG_FORMAT, "%s%s: 0x%02x (%u) in %u bits%s", indent_str, txt, value, value, length, valid_str);
|
||||
break;
|
||||
case VC_CONTAINER_BITS_LOG_U16:
|
||||
vc_container_log(p_ctx, VC_CONTAINER_LOG_FORMAT, "%s%s: 0x%04x (%u) in %u bits%s", indent_str, txt, value, value, length, valid_str);
|
||||
break;
|
||||
case VC_CONTAINER_BITS_LOG_U32:
|
||||
vc_container_log(p_ctx, VC_CONTAINER_LOG_FORMAT, "%s%s: 0x%08x (%u) in %u bits%s", indent_str, txt, value, value, length, valid_str);
|
||||
break;
|
||||
case VC_CONTAINER_BITS_LOG_EG_U32:
|
||||
vc_container_log(p_ctx, VC_CONTAINER_LOG_FORMAT, "%s%s: 0x%08x (%u) unsigned Exp-Golomb%s", indent_str, txt, value, value, valid_str);
|
||||
break;
|
||||
default:
|
||||
/* Unexpected operation. Check bit stream logging macros */
|
||||
vc_container_assert(0);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int32_t vc_container_bits_log_s32(VC_CONTAINER_T *p_ctx,
|
||||
uint32_t indent,
|
||||
const char *txt,
|
||||
VC_CONTAINER_BITS_T *bit_stream,
|
||||
VC_CONTAINER_BITS_LOG_OP_T op,
|
||||
uint32_t length,
|
||||
int32_t value)
|
||||
{
|
||||
const char *valid_str = vc_container_bits_valid_str(bit_stream);
|
||||
const char *indent_str = vc_container_bits_indent_str(indent);
|
||||
|
||||
VC_CONTAINER_PARAM_UNUSED(length);
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case VC_CONTAINER_BITS_LOG_EG_S32:
|
||||
vc_container_log(p_ctx, VC_CONTAINER_LOG_FORMAT, "%s%s: 0x%08x (%d) signed Exp-Golomb%s", indent_str, txt, value, value, valid_str);
|
||||
break;
|
||||
default:
|
||||
/* Unexpected operation. Check bit stream logging macros */
|
||||
vc_container_assert(0);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
#endif /* ENABLE_CONTAINERS_LOG_FORMAT */
|
344
gfx/include/userland/containers/core/containers_bits.h
Normal file
344
gfx/include/userland/containers/core/containers_bits.h
Normal file
@ -0,0 +1,344 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef VC_CONTAINERS_BITS_H
|
||||
#define VC_CONTAINERS_BITS_H
|
||||
|
||||
#include "containers/containers.h"
|
||||
|
||||
/** Bit stream structure
|
||||
* Value are read from the buffer, taking bits from MSB to LSB in sequential
|
||||
* bytes until the number of bit and the number of bytes runs out. */
|
||||
typedef struct vc_container_bits_tag
|
||||
{
|
||||
const uint8_t *buffer; /**< Buffer from which to take bits */
|
||||
uint32_t bytes; /**< Number of bytes available from buffer */
|
||||
uint32_t bits; /**< Number of bits available at current pointer */
|
||||
} VC_CONTAINER_BITS_T;
|
||||
|
||||
/** Initialise a bit stream object.
|
||||
*
|
||||
* \pre bit_stream is not NULL.
|
||||
*
|
||||
* \param bit_stream The bit stream object to initialise.
|
||||
* \param buffer Pointer to the start of the byte buffer.
|
||||
* \param available Number of bytes in the bit stream.
|
||||
*/
|
||||
void vc_container_bits_init(VC_CONTAINER_BITS_T *bit_stream, const uint8_t *buffer, uint32_t available);
|
||||
|
||||
/** Invalidates the bit stream.
|
||||
* Also returns zero, because it allows callers that need to invalidate and
|
||||
* immediately return zero to do so in a single statement.
|
||||
*
|
||||
* \pre bit_stream is not NULL.
|
||||
*
|
||||
* \param bit_stream The bit stream object.
|
||||
* \return Zero, always.
|
||||
*/
|
||||
uint32_t vc_container_bits_invalidate( VC_CONTAINER_BITS_T *bit_stream );
|
||||
|
||||
/** Returns true if the bit stream is currently valid.
|
||||
* The stream becomes invalid when a read or skip operation goe beyond the end
|
||||
* of the stream.
|
||||
*
|
||||
* \pre bit_stream is not NULL.
|
||||
*
|
||||
* \param bit_stream The bit stream object.
|
||||
* \return True if the stream is valid, false if it is invalid.
|
||||
*/
|
||||
bool vc_container_bits_valid(VC_CONTAINER_BITS_T *bit_stream);
|
||||
|
||||
/** Reset a valid bit stream object to appear empty.
|
||||
* Once a stream has become invalid, reset has no effect.
|
||||
*
|
||||
* \pre bit_stream is not NULL.
|
||||
*
|
||||
* \param bit_stream The bit stream object.
|
||||
*/
|
||||
void vc_container_bits_reset(VC_CONTAINER_BITS_T *bit_stream);
|
||||
|
||||
/** Return the current byte pointer for the bit stream.
|
||||
*
|
||||
* \pre bit_stream is not NULL.
|
||||
* \pre The stream is on a byte boundary.
|
||||
*
|
||||
* \param bit_stream The bit stream object.
|
||||
* \return The current byte pointer, or NULL if the stream is invalid.
|
||||
*/
|
||||
const uint8_t *vc_container_bits_current_pointer(const VC_CONTAINER_BITS_T *bit_stream);
|
||||
|
||||
/** Copy one bit stream to another.
|
||||
* If the source stream is invalid, the destination one will become so as well.
|
||||
*
|
||||
* \pre Neither bit stream is NULL.
|
||||
*
|
||||
* \param dst The destination bit stream object.
|
||||
* \param src The source bit stream object.
|
||||
*/
|
||||
void vc_container_bits_copy_stream(VC_CONTAINER_BITS_T *dst, const VC_CONTAINER_BITS_T *src);
|
||||
|
||||
/** Return the number of bits left to take from the stream.
|
||||
* If the stream is invalid, zero is returned.
|
||||
*
|
||||
* \pre bit_stream is not NULL.
|
||||
*
|
||||
* \param bit_stream The bit stream object.
|
||||
* \return The number of bits left to take.
|
||||
*/
|
||||
uint32_t vc_container_bits_available(const VC_CONTAINER_BITS_T *bit_stream);
|
||||
|
||||
/** Return the number of bytes left to take from the stream.
|
||||
* If the stream is invalid, zero is returned.
|
||||
*
|
||||
* \pre bit_stream is not NULL.
|
||||
*
|
||||
* \param bit_stream The bit stream object.
|
||||
* \return The number of bytes left to take.
|
||||
*/
|
||||
uint32_t vc_container_bits_bytes_available(const VC_CONTAINER_BITS_T *bit_stream);
|
||||
|
||||
/** Skip past a number of bits in the stream.
|
||||
* If bits_to_skip is greater than the number of bits available in the stream,
|
||||
* the stream becomes invalid.
|
||||
* If the stream is already invalid, this has no effect.
|
||||
*
|
||||
* \pre bit_stream is not NULL.
|
||||
*
|
||||
* \param bit_stream The bit stream object.
|
||||
* \param bits_to_skip The number of bits to skip.
|
||||
*/
|
||||
void vc_container_bits_skip(VC_CONTAINER_BITS_T *bit_stream, uint32_t bits_to_skip);
|
||||
|
||||
/** Skip past a number of bytes in the stream.
|
||||
* If bytes_to_skip is greater than the number of bytes available in the stream,
|
||||
* the stream becomes invalid.
|
||||
* If the stream is already invalid, this has no effect.
|
||||
*
|
||||
* \pre bit_stream is not NULL.
|
||||
* \pre The stream is on a byte boundary.
|
||||
*
|
||||
* \param bit_stream The bit stream object.
|
||||
* \param bytes_to_skip The number of bytes to skip.
|
||||
*/
|
||||
void vc_container_bits_skip_bytes(VC_CONTAINER_BITS_T *bit_stream, uint32_t bytes_to_skip);
|
||||
|
||||
/** Reduce the length of the bit stream by a number of bytes.
|
||||
* This reduces the number of bits/bytes available without changing the current
|
||||
* position in the stream. If bytes_to_reduce is greater than the number of
|
||||
* bytes available in the stream, the stream becomes invalid.
|
||||
* If the stream is already invalid, this has no effect.
|
||||
*
|
||||
* \pre bit_stream is not NULL.
|
||||
*
|
||||
* \param bit_stream The bit stream object.
|
||||
* \param bytes_to_reduce The number of bytes by which to reduce the stream.
|
||||
*/
|
||||
void vc_container_bits_reduce_bytes(VC_CONTAINER_BITS_T *bit_stream, uint32_t bytes_to_reduce);
|
||||
|
||||
/** Copies a number of bytes from the stream to a byte buffer.
|
||||
* If the stream is or becomes invalid, no data is copied.
|
||||
*
|
||||
* \pre bit_stream is not NULL.
|
||||
* \pre The stream is on a byte boundary.
|
||||
*
|
||||
* \param bit_stream The bit stream object.
|
||||
* \param bytes_to_copy The number of bytes to copy.
|
||||
* \param dst The byte buffer destination.
|
||||
*/
|
||||
void vc_container_bits_copy_bytes(VC_CONTAINER_BITS_T *bit_stream, uint32_t bytes_to_copy, uint8_t *dst);
|
||||
|
||||
/** Returns the next value_bits from the stream. The last bit will be the least
|
||||
* significant bit in the returned value.
|
||||
* If value_bits is greater than the number of bits available in the stream,
|
||||
* the stream becomes invalid.
|
||||
* If the stream is invalid, or becomes invalid while reading the value, zero
|
||||
* is returned.
|
||||
*
|
||||
* \pre bit_stream is not NULL.
|
||||
* \pre value_bits is not larger than 32.
|
||||
*
|
||||
* \param bit_stream The bit stream object.
|
||||
* \param value_bits The number of bits to retrieve.
|
||||
* \return The value read from the stream, or zero if the stream is invalid.
|
||||
*/
|
||||
uint32_t vc_container_bits_read_u32(VC_CONTAINER_BITS_T *bit_stream, uint32_t value_bits);
|
||||
|
||||
/** Skips the next Exp-Golomb value in the stream.
|
||||
* See section 9.1 of ITU-T REC H.264 201003 for details.
|
||||
* If there are not enough bits in the stream to complete an Exp-Golomb value,
|
||||
* the stream becomes invalid.
|
||||
* If the stream is already invalid, this has no effect.
|
||||
*
|
||||
* \pre bit_stream is not NULL.
|
||||
*
|
||||
* \param bit_stream The bit stream object.
|
||||
*/
|
||||
void vc_container_bits_skip_exp_golomb(VC_CONTAINER_BITS_T *bit_stream);
|
||||
|
||||
/** Returns the next unsigned Exp-Golomb value from the stream.
|
||||
* See section 9.1 of ITU-T REC H.264 201003 for details.
|
||||
* If there are not enough bits in the stream to complete an Exp-Golomb value,
|
||||
* the stream becomes invalid.
|
||||
* If the next unsigned Exp-Golomb value in the stream is larger than 32 bits,
|
||||
* or the stream is or becomes invalid, zero is returned.
|
||||
*
|
||||
* \pre bit_stream is not NULL.
|
||||
*
|
||||
* \param bit_stream The bit stream object.
|
||||
* \return The next unsigned value from the stream, or zero on error.
|
||||
*/
|
||||
uint32_t vc_container_bits_read_u32_exp_golomb(VC_CONTAINER_BITS_T *bit_stream);
|
||||
|
||||
/** Returns the next signed Exp-Golomb value from the stream.
|
||||
* See section 9.1.1 of ITU-T REC H.264 201003 for details.
|
||||
* If there are not enough bits in the stream to complete an Exp-Golomb value,
|
||||
* the stream becomes invalid.
|
||||
* If the next signed Exp-Golomb value in the stream is larger than 32 bits,
|
||||
* or the stream is or becomes invalid, zero is returned.
|
||||
*
|
||||
* \pre bit_stream is not NULL.
|
||||
*
|
||||
* \param bit_stream The bit stream object.
|
||||
* \return The next signed value from the stream, or zero on error.
|
||||
*/
|
||||
int32_t vc_container_bits_read_s32_exp_golomb(VC_CONTAINER_BITS_T *bit_stream);
|
||||
|
||||
/******************************************************************************
|
||||
* Macros reduce function name length and enable logging of some operations *
|
||||
******************************************************************************/
|
||||
#define BITS_INIT(ctx, bits, buffer, available) (VC_CONTAINER_PARAM_UNUSED(ctx), vc_container_bits_init(bits, buffer, available))
|
||||
#define BITS_INVALIDATE(ctx, bits) (VC_CONTAINER_PARAM_UNUSED(ctx), vc_container_bits_invalidate(bits))
|
||||
#define BITS_VALID(ctx, bits) (VC_CONTAINER_PARAM_UNUSED(ctx), vc_container_bits_valid(bits))
|
||||
#define BITS_RESET(ctx, bits) (VC_CONTAINER_PARAM_UNUSED(ctx), vc_container_bits_reset(bits))
|
||||
#define BITS_AVAILABLE(ctx, bits) (VC_CONTAINER_PARAM_UNUSED(ctx), vc_container_bits_available(bits))
|
||||
#define BITS_BYTES_AVAILABLE(ctx, bits) (VC_CONTAINER_PARAM_UNUSED(ctx), vc_container_bits_bytes_available(bits))
|
||||
#define BITS_CURRENT_POINTER(ctx, bits) (VC_CONTAINER_PARAM_UNUSED(ctx), vc_container_bits_current_pointer(bits))
|
||||
#define BITS_COPY_STREAM(ctx, dst, src) (VC_CONTAINER_PARAM_UNUSED(ctx), vc_container_bits_copy_stream(dst, src))
|
||||
|
||||
#ifdef ENABLE_CONTAINERS_LOG_FORMAT
|
||||
|
||||
typedef enum {
|
||||
VC_CONTAINER_BITS_LOG_SKIP,
|
||||
VC_CONTAINER_BITS_LOG_SKIP_BYTES,
|
||||
VC_CONTAINER_BITS_LOG_U8,
|
||||
VC_CONTAINER_BITS_LOG_U16,
|
||||
VC_CONTAINER_BITS_LOG_U32,
|
||||
VC_CONTAINER_BITS_LOG_COPY_BYTES,
|
||||
VC_CONTAINER_BITS_LOG_REDUCE_BYTES,
|
||||
VC_CONTAINER_BITS_LOG_EG_SKIP,
|
||||
VC_CONTAINER_BITS_LOG_EG_U32,
|
||||
VC_CONTAINER_BITS_LOG_EG_S32,
|
||||
} VC_CONTAINER_BITS_LOG_OP_T;
|
||||
|
||||
/** Logs an operation with void return.
|
||||
*
|
||||
* \pre None of p_ctx, txt or bit_stream are NULL.
|
||||
*
|
||||
* \param p_ctx Container context.
|
||||
* \param indent Indent level.
|
||||
* \param txt Description of what is being read.
|
||||
* \param bit_stream The bit stream object.
|
||||
* \param op The operation just performed.
|
||||
* \param length The length of the operation.
|
||||
*/
|
||||
void vc_container_bits_log(VC_CONTAINER_T *p_ctx, uint32_t indent, const char *txt, VC_CONTAINER_BITS_T *bit_stream, VC_CONTAINER_BITS_LOG_OP_T op, uint32_t length);
|
||||
|
||||
/** Logs an operation with unsigned 32-bit integer return.
|
||||
*
|
||||
* \pre None of p_ctx, txt or bit_stream are NULL.
|
||||
*
|
||||
* \param p_ctx Container context.
|
||||
* \param indent Indent level.
|
||||
* \param txt Description of what is being read.
|
||||
* \param bit_stream The bit stream object.
|
||||
* \param op The operation just performed.
|
||||
* \param length The length of the operation.
|
||||
* \param value The value returned by the operation.
|
||||
* \return The unsigned 32-bit integer value passed in.
|
||||
*/
|
||||
uint32_t vc_container_bits_log_u32(VC_CONTAINER_T *p_ctx, uint32_t indent, const char *txt, VC_CONTAINER_BITS_T *bit_stream, VC_CONTAINER_BITS_LOG_OP_T op, uint32_t length, uint32_t value);
|
||||
|
||||
/** Logs an operation with signed 32-bit integer return.
|
||||
*
|
||||
* \pre None of p_ctx, txt or bit_stream are NULL.
|
||||
*
|
||||
* \param p_ctx Container context.
|
||||
* \param indent Indent level.
|
||||
* \param txt Description of what is being read.
|
||||
* \param bit_stream The bit stream object.
|
||||
* \param op The operation just performed.
|
||||
* \param length The length of the operation.
|
||||
* \param value The value returned by the operation.
|
||||
* \return The signed 32-bit integer value passed in.
|
||||
*/
|
||||
int32_t vc_container_bits_log_s32(VC_CONTAINER_T *p_ctx, uint32_t indent, const char *txt, VC_CONTAINER_BITS_T *bit_stream, VC_CONTAINER_BITS_LOG_OP_T op, uint32_t length, int32_t value);
|
||||
|
||||
#ifndef BITS_LOG_INDENT
|
||||
# ifndef CONTAINER_HELPER_LOG_INDENT
|
||||
# define BITS_LOG_INDENT(ctx) 0
|
||||
# else
|
||||
# define BITS_LOG_INDENT(ctx) ((ctx)->priv->io->module ? CONTAINER_HELPER_LOG_INDENT(a) : 0)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#define BITS_SKIP(ctx, bits, length, txt) (vc_container_bits_skip(bits, length), vc_container_bits_log(ctx, BITS_LOG_INDENT(ctx), txt, bits, VC_CONTAINER_BITS_LOG_SKIP, length))
|
||||
#define BITS_SKIP_BYTES(ctx, bits, length, txt) (vc_container_bits_skip_bytes(bits, length), vc_container_bits_log(ctx, BITS_LOG_INDENT(ctx), txt, bits, VC_CONTAINER_BITS_LOG_SKIP_BYTES, length))
|
||||
|
||||
#define BITS_READ_U8(ctx, bits, length, txt) (uint8_t)vc_container_bits_log_u32(ctx, BITS_LOG_INDENT(ctx), txt, bits, VC_CONTAINER_BITS_LOG_U8, length, vc_container_bits_read_u32(bits, length))
|
||||
#define BITS_READ_U16(ctx, bits, length, txt) (uint16_t)vc_container_bits_log_u32(ctx, BITS_LOG_INDENT(ctx), txt, bits, VC_CONTAINER_BITS_LOG_U16, length, vc_container_bits_read_u32(bits, length))
|
||||
#define BITS_READ_U32(ctx, bits, length, txt) vc_container_bits_log_u32(ctx, BITS_LOG_INDENT(ctx), txt, bits, VC_CONTAINER_BITS_LOG_U32, length, vc_container_bits_read_u32(bits, length))
|
||||
|
||||
#define BITS_COPY_BYTES(ctx, bits, length, dst, txt) (vc_container_bits_copy_bytes(bits, length, dst), vc_container_bits_log(ctx, BITS_LOG_INDENT(ctx), txt, bits, VC_CONTAINER_BITS_LOG_COPY_BYTES, length))
|
||||
|
||||
#define BITS_REDUCE_BYTES(ctx, bits, length, txt) (vc_container_bits_reduce_bytes(bits, length), vc_container_bits_log(ctx, BITS_LOG_INDENT(ctx), txt, bits, VC_CONTAINER_BITS_LOG_REDUCE_BYTES, length))
|
||||
|
||||
#define BITS_SKIP_EXP(ctx, bits, txt) (vc_container_bits_skip_exp_golomb(bits), vc_container_bits_log(ctx, BITS_LOG_INDENT(ctx), txt, bits, VC_CONTAINER_BITS_LOG_EG_SKIP, 0))
|
||||
|
||||
#define BITS_READ_S32_EXP(ctx, bits, txt) vc_container_bits_log_s32(ctx, BITS_LOG_INDENT(ctx), txt, bits, VC_CONTAINER_BITS_LOG_EG_S32, 0, vc_container_bits_read_s32_exp_golomb(bits))
|
||||
#define BITS_READ_U32_EXP(ctx, bits, txt) vc_container_bits_log_u32(ctx, BITS_LOG_INDENT(ctx), txt, bits, VC_CONTAINER_BITS_LOG_EG_U32, 0, vc_container_bits_read_u32_exp_golomb(bits))
|
||||
|
||||
#else /* ENABLE_CONTAINERS_LOG_FORMAT */
|
||||
|
||||
#define BITS_SKIP(ctx, bits, length, txt) (VC_CONTAINER_PARAM_UNUSED(ctx), VC_CONTAINER_PARAM_UNUSED(txt), vc_container_bits_skip(bits, length))
|
||||
#define BITS_SKIP_BYTES(ctx, bits, length, txt) (VC_CONTAINER_PARAM_UNUSED(ctx), VC_CONTAINER_PARAM_UNUSED(txt), vc_container_bits_skip_bytes(bits, length))
|
||||
|
||||
#define BITS_READ_U8(ctx, bits, length, txt) (uint8_t)(VC_CONTAINER_PARAM_UNUSED(ctx), VC_CONTAINER_PARAM_UNUSED(txt), vc_container_bits_read_u32(bits, length))
|
||||
#define BITS_READ_U16(ctx, bits, length, txt) (uint16_t)(VC_CONTAINER_PARAM_UNUSED(ctx), VC_CONTAINER_PARAM_UNUSED(txt), vc_container_bits_read_u32(bits, length))
|
||||
#define BITS_READ_U32(ctx, bits, length, txt) (VC_CONTAINER_PARAM_UNUSED(ctx), VC_CONTAINER_PARAM_UNUSED(txt), vc_container_bits_read_u32(bits, length))
|
||||
|
||||
#define BITS_COPY_BYTES(ctx, bits, length, dst, txt) (VC_CONTAINER_PARAM_UNUSED(ctx), VC_CONTAINER_PARAM_UNUSED(txt), vc_container_bits_copy_bytes(bits, length, dst))
|
||||
|
||||
#define BITS_REDUCE_BYTES(ctx, bits, length, txt) (VC_CONTAINER_PARAM_UNUSED(ctx), VC_CONTAINER_PARAM_UNUSED(txt), vc_container_bits_reduce_bytes(bits, length))
|
||||
|
||||
#define BITS_SKIP_EXP(ctx, bits, txt) (VC_CONTAINER_PARAM_UNUSED(ctx), VC_CONTAINER_PARAM_UNUSED(txt), vc_container_bits_skip_exp_golomb(bits))
|
||||
|
||||
#define BITS_READ_S32_EXP(ctx, bits, txt) (VC_CONTAINER_PARAM_UNUSED(ctx), VC_CONTAINER_PARAM_UNUSED(txt), vc_container_bits_read_s32_exp_golomb(bits))
|
||||
#define BITS_READ_U32_EXP(ctx, bits, txt) (VC_CONTAINER_PARAM_UNUSED(ctx), VC_CONTAINER_PARAM_UNUSED(txt), vc_container_bits_read_u32_exp_golomb(bits))
|
||||
|
||||
#endif /* ENABLE_CONTAINERS_LOG_FORMAT */
|
||||
|
||||
#endif /* VC_CONTAINERS_BITS_H */
|
389
gfx/include/userland/containers/core/containers_bytestream.h
Normal file
389
gfx/include/userland/containers/core/containers_bytestream.h
Normal file
@ -0,0 +1,389 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef VC_CONTAINERS_BYTESTREAM_H
|
||||
#define VC_CONTAINERS_BYTESTREAM_H
|
||||
|
||||
/** \file
|
||||
* Utility functions to provide a byte stream out of a list of container packets
|
||||
*/
|
||||
|
||||
typedef struct VC_CONTAINER_BYTESTREAM_T
|
||||
{
|
||||
VC_CONTAINER_PACKET_T *first; /**< first packet in the chain */
|
||||
VC_CONTAINER_PACKET_T **last; /**< last packet in the chain */
|
||||
|
||||
VC_CONTAINER_PACKET_T *current; /**< packet containing the current read pointer */
|
||||
size_t current_offset; /**< position of current packet (in bytes) */
|
||||
size_t offset; /**< position within the current packet */
|
||||
|
||||
size_t bytes; /**< Number of bytes available in the bytestream */
|
||||
|
||||
} VC_CONTAINER_BYTESTREAM_T;
|
||||
|
||||
/*****************************************************************************/
|
||||
STATIC_INLINE void bytestream_init( VC_CONTAINER_BYTESTREAM_T *stream )
|
||||
{
|
||||
stream->first = stream->current = NULL;
|
||||
stream->last = &stream->first;
|
||||
stream->offset = stream->current_offset = stream->bytes = 0;
|
||||
}
|
||||
|
||||
STATIC_INLINE void bytestream_push( VC_CONTAINER_BYTESTREAM_T *stream,
|
||||
VC_CONTAINER_PACKET_T *packet )
|
||||
{
|
||||
*stream->last = packet;
|
||||
stream->last = &packet->next;
|
||||
packet->next = NULL;
|
||||
if( !stream->current ) stream->current = packet;
|
||||
stream->bytes += packet->size;
|
||||
}
|
||||
|
||||
STATIC_INLINE VC_CONTAINER_PACKET_T *bytestream_pop( VC_CONTAINER_BYTESTREAM_T *stream )
|
||||
{
|
||||
VC_CONTAINER_PACKET_T *packet = stream->first;
|
||||
|
||||
if( stream->current == packet )
|
||||
return NULL;
|
||||
vc_container_assert(packet);
|
||||
|
||||
stream->bytes -= packet->size;
|
||||
stream->current_offset -= packet->size;
|
||||
stream->first = packet->next;
|
||||
if( !stream->first )
|
||||
stream->last = &stream->first;
|
||||
return packet;
|
||||
}
|
||||
|
||||
STATIC_INLINE VC_CONTAINER_PACKET_T *bytestream_get_packet( VC_CONTAINER_BYTESTREAM_T *stream, size_t *offset )
|
||||
{
|
||||
VC_CONTAINER_PACKET_T *packet = stream->current;
|
||||
size_t off = stream->offset;
|
||||
|
||||
while(packet && packet->size == off)
|
||||
{
|
||||
packet = packet->next;
|
||||
off = 0;
|
||||
}
|
||||
|
||||
if (offset)
|
||||
*offset = off;
|
||||
|
||||
return packet;
|
||||
}
|
||||
|
||||
STATIC_INLINE bool bytestream_skip_packet( VC_CONTAINER_BYTESTREAM_T *stream )
|
||||
{
|
||||
VC_CONTAINER_PACKET_T *packet = stream->current;
|
||||
|
||||
if( packet )
|
||||
{
|
||||
stream->current = packet->next;
|
||||
stream->current_offset += (packet->size - stream->offset);
|
||||
stream->offset = 0;
|
||||
}
|
||||
|
||||
return !!packet;
|
||||
}
|
||||
|
||||
STATIC_INLINE void bytestream_get_timestamps( VC_CONTAINER_BYTESTREAM_T *stream, int64_t *pts, int64_t *dts, bool b_same )
|
||||
{
|
||||
VC_CONTAINER_PACKET_T *packet = bytestream_get_packet( stream, 0 );
|
||||
|
||||
if(packet)
|
||||
{
|
||||
if(b_same && packet->pts == VC_CONTAINER_TIME_UNKNOWN) packet->pts = packet->dts;
|
||||
if(pts) *pts = packet->pts;
|
||||
if(dts) *dts = packet->dts;
|
||||
|
||||
packet->pts = packet->dts = VC_CONTAINER_TIME_UNKNOWN;
|
||||
return;
|
||||
}
|
||||
|
||||
if(pts) *pts = VC_CONTAINER_TIME_UNKNOWN;
|
||||
if(dts) *dts = VC_CONTAINER_TIME_UNKNOWN;
|
||||
}
|
||||
|
||||
STATIC_INLINE void bytestream_get_timestamps_and_offset( VC_CONTAINER_BYTESTREAM_T *stream,
|
||||
int64_t *pts, int64_t *dts, size_t *offset, bool b_same )
|
||||
{
|
||||
VC_CONTAINER_PACKET_T *packet = bytestream_get_packet( stream, offset );
|
||||
|
||||
if(packet)
|
||||
{
|
||||
if(b_same && packet->pts == VC_CONTAINER_TIME_UNKNOWN) packet->pts = packet->dts;
|
||||
if(pts) *pts = packet->pts;
|
||||
if(dts) *dts = packet->dts;
|
||||
|
||||
packet->pts = packet->dts = VC_CONTAINER_TIME_UNKNOWN;
|
||||
return;
|
||||
}
|
||||
|
||||
if(pts) *pts = VC_CONTAINER_TIME_UNKNOWN;
|
||||
if(dts) *dts = VC_CONTAINER_TIME_UNKNOWN;
|
||||
}
|
||||
|
||||
STATIC_INLINE size_t bytestream_size( VC_CONTAINER_BYTESTREAM_T *stream )
|
||||
{
|
||||
return stream->bytes - stream->current_offset - stream->offset;
|
||||
}
|
||||
|
||||
STATIC_INLINE VC_CONTAINER_STATUS_T bytestream_skip( VC_CONTAINER_BYTESTREAM_T *stream, size_t size )
|
||||
{
|
||||
VC_CONTAINER_PACKET_T *packet;
|
||||
size_t offset, bytes = 0, skip;
|
||||
|
||||
if( !size )
|
||||
return VC_CONTAINER_SUCCESS; /* Nothing to do */
|
||||
if( stream->bytes - stream->current_offset - stream->offset < size )
|
||||
return VC_CONTAINER_ERROR_EOS; /* Not enough data */
|
||||
|
||||
for( packet = stream->current, offset = stream->offset; ;
|
||||
packet = packet->next, offset = 0 )
|
||||
{
|
||||
if( packet->size - offset >= size)
|
||||
break;
|
||||
|
||||
skip = packet->size - offset;
|
||||
bytes += skip;
|
||||
size -= skip;
|
||||
}
|
||||
|
||||
stream->current = packet;
|
||||
stream->current_offset += stream->offset - offset + bytes;
|
||||
stream->offset = offset + size;
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
STATIC_INLINE VC_CONTAINER_STATUS_T bytestream_get( VC_CONTAINER_BYTESTREAM_T *stream, uint8_t *data, size_t size )
|
||||
{
|
||||
VC_CONTAINER_PACKET_T *packet;
|
||||
size_t offset, bytes = 0, copy;
|
||||
|
||||
if( !size )
|
||||
return VC_CONTAINER_SUCCESS; /* Nothing to do */
|
||||
if( stream->bytes - stream->current_offset - stream->offset < size )
|
||||
return VC_CONTAINER_ERROR_EOS; /* Not enough data */
|
||||
|
||||
for( packet = stream->current, offset = stream->offset; ;
|
||||
packet = packet->next, offset = 0 )
|
||||
{
|
||||
if( packet->size - offset >= size)
|
||||
break;
|
||||
|
||||
copy = packet->size - offset;
|
||||
memcpy( data, packet->data + offset, copy );
|
||||
bytes += copy;
|
||||
data += copy;
|
||||
size -= copy;
|
||||
}
|
||||
|
||||
memcpy( data, packet->data + offset, size );
|
||||
stream->current = packet;
|
||||
stream->current_offset += stream->offset - offset + bytes;
|
||||
stream->offset = offset + size;
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
STATIC_INLINE VC_CONTAINER_STATUS_T bytestream_peek( VC_CONTAINER_BYTESTREAM_T *stream, uint8_t *data, size_t size )
|
||||
{
|
||||
VC_CONTAINER_PACKET_T *packet;
|
||||
size_t offset, copy;
|
||||
|
||||
if( !size )
|
||||
return VC_CONTAINER_SUCCESS; /* Nothing to do */
|
||||
if( stream->bytes - stream->current_offset - stream->offset < size )
|
||||
return VC_CONTAINER_ERROR_EOS; /* Not enough data */
|
||||
|
||||
for( packet = stream->current, offset = stream->offset; ;
|
||||
packet = packet->next, offset = 0 )
|
||||
{
|
||||
if( packet->size - offset >= size)
|
||||
break;
|
||||
|
||||
copy = packet->size - offset;
|
||||
memcpy( data, packet->data + offset, copy );
|
||||
data += copy;
|
||||
size -= copy;
|
||||
}
|
||||
|
||||
memcpy( data, packet->data + offset, size );
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
STATIC_INLINE VC_CONTAINER_STATUS_T bytestream_peek_at( VC_CONTAINER_BYTESTREAM_T *stream,
|
||||
size_t peek_offset, uint8_t *data, size_t size )
|
||||
{
|
||||
VC_CONTAINER_PACKET_T *packet;
|
||||
size_t copy;
|
||||
|
||||
if( !size )
|
||||
return VC_CONTAINER_SUCCESS; /* Nothing to do */
|
||||
if( stream->bytes - stream->current_offset - stream->offset < peek_offset + size )
|
||||
return VC_CONTAINER_ERROR_EOS; /* Not enough data */
|
||||
|
||||
peek_offset += stream->offset;
|
||||
|
||||
/* Find the right place */
|
||||
for( packet = stream->current; ; packet = packet->next )
|
||||
{
|
||||
if( packet->size > peek_offset )
|
||||
break;
|
||||
|
||||
peek_offset -= packet->size;
|
||||
}
|
||||
|
||||
/* Copy the data */
|
||||
for( ; ; packet = packet->next, peek_offset = 0 )
|
||||
{
|
||||
if( packet->size - peek_offset >= size)
|
||||
break;
|
||||
|
||||
copy = packet->size - peek_offset;
|
||||
memcpy( data, packet->data + peek_offset, copy );
|
||||
data += copy;
|
||||
size -= copy;
|
||||
}
|
||||
|
||||
memcpy( data, packet->data + peek_offset, size );
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
STATIC_INLINE VC_CONTAINER_STATUS_T bytestream_skip_byte( VC_CONTAINER_BYTESTREAM_T *stream )
|
||||
{
|
||||
VC_CONTAINER_PACKET_T *packet = stream->current;
|
||||
|
||||
if( !packet )
|
||||
return VC_CONTAINER_ERROR_EOS;
|
||||
|
||||
/* Fast path first */
|
||||
if( packet->size - stream->offset )
|
||||
{
|
||||
stream->offset++;
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
return bytestream_skip( stream, 1 );
|
||||
}
|
||||
|
||||
STATIC_INLINE VC_CONTAINER_STATUS_T packet_peek_byte( VC_CONTAINER_BYTESTREAM_T *stream,
|
||||
uint8_t *data )
|
||||
{
|
||||
VC_CONTAINER_PACKET_T *packet = stream->current;
|
||||
|
||||
if( !packet )
|
||||
return VC_CONTAINER_ERROR_EOS;
|
||||
|
||||
/* Fast path first */
|
||||
if( packet->size - stream->offset )
|
||||
{
|
||||
*data = packet->data[stream->offset];
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
return bytestream_peek( stream, data, 1 );
|
||||
}
|
||||
|
||||
STATIC_INLINE VC_CONTAINER_STATUS_T packet_get_byte( VC_CONTAINER_BYTESTREAM_T *stream,
|
||||
uint8_t *data )
|
||||
{
|
||||
VC_CONTAINER_PACKET_T *packet = stream->current;
|
||||
|
||||
if( !packet )
|
||||
return VC_CONTAINER_ERROR_EOS;
|
||||
|
||||
/* Fast path first */
|
||||
if( packet->size - stream->offset )
|
||||
{
|
||||
*data = packet->data[stream->offset];
|
||||
stream->offset++;
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
return bytestream_get( stream, data, 1 );
|
||||
}
|
||||
|
||||
STATIC_INLINE VC_CONTAINER_STATUS_T bytestream_find_startcode( VC_CONTAINER_BYTESTREAM_T *stream,
|
||||
size_t *search_offset, const uint8_t *startcode, unsigned int length )
|
||||
{
|
||||
VC_CONTAINER_PACKET_T *packet, *backup_packet = NULL;
|
||||
size_t position, start_offset = position = *search_offset;
|
||||
size_t offset, backup_offset = 0;
|
||||
unsigned int match = 0;
|
||||
|
||||
if( stream->bytes - stream->current_offset - stream->offset < start_offset + length )
|
||||
return VC_CONTAINER_ERROR_EOS; /* Not enough data */
|
||||
|
||||
/* Find the right place */
|
||||
for( packet = stream->current, offset = stream->offset;
|
||||
packet != NULL; packet = packet->next, offset = 0 )
|
||||
{
|
||||
if( packet->size - offset > start_offset)
|
||||
break;
|
||||
|
||||
start_offset -= (packet->size - offset);
|
||||
}
|
||||
|
||||
/* Start the search for the start code.
|
||||
* To make things simple we try to find a match one byte at a time. */
|
||||
for( offset += start_offset;
|
||||
packet != NULL; packet = packet->next, offset = 0 )
|
||||
{
|
||||
for( ; offset < packet->size; offset++ )
|
||||
{
|
||||
if( packet->data[offset] != startcode[match] )
|
||||
{
|
||||
if ( match ) /* False positive */
|
||||
{
|
||||
packet = backup_packet;
|
||||
offset = backup_offset;
|
||||
match = 0;
|
||||
}
|
||||
position++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* We've got a match */
|
||||
if( !match++ )
|
||||
{
|
||||
backup_packet = packet;
|
||||
backup_offset = offset;
|
||||
}
|
||||
|
||||
if( match == length )
|
||||
{
|
||||
/* We have the full start code it */
|
||||
*search_offset = position;
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*search_offset = position;
|
||||
return VC_CONTAINER_ERROR_EOS; /* No luck in finding the start code */
|
||||
}
|
||||
|
||||
#endif /* VC_CONTAINERS_BYTESTREAM_H */
|
209
gfx/include/userland/containers/core/containers_codecs.c
Normal file
209
gfx/include/userland/containers/core/containers_codecs.c
Normal file
@ -0,0 +1,209 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "containers/containers.h"
|
||||
#include "containers/containers_codecs.h"
|
||||
#include "containers/core/containers_utils.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
static struct {
|
||||
VC_CONTAINER_FOURCC_T codec;
|
||||
uint16_t id;
|
||||
} codec_to_wf_table[] =
|
||||
{
|
||||
{VC_CONTAINER_CODEC_PCM_SIGNED_LE, WAVE_FORMAT_PCM},
|
||||
{VC_CONTAINER_CODEC_ALAW, WAVE_FORMAT_ALAW},
|
||||
{VC_CONTAINER_CODEC_MULAW, WAVE_FORMAT_MULAW},
|
||||
{VC_CONTAINER_CODEC_ADPCM_MS, WAVE_FORMAT_ADPCM},
|
||||
{VC_CONTAINER_CODEC_MPGA, WAVE_FORMAT_MPEG},
|
||||
{VC_CONTAINER_CODEC_MPGA, WAVE_FORMAT_MPEGLAYER3},
|
||||
{VC_CONTAINER_CODEC_WMA1, WAVE_FORMAT_WMAUDIO1},
|
||||
{VC_CONTAINER_CODEC_WMA2, WAVE_FORMAT_WMAUDIO2},
|
||||
{VC_CONTAINER_CODEC_WMAP, WAVE_FORMAT_WMAUDIOPRO},
|
||||
{VC_CONTAINER_CODEC_WMAL, WAVE_FORMAT_WMAUDIO_LOSSLESS},
|
||||
{VC_CONTAINER_CODEC_WMAV, WAVE_FORMAT_WMAUDIO_VOICE},
|
||||
{VC_CONTAINER_CODEC_AC3, WAVE_FORMAT_DVM},
|
||||
{VC_CONTAINER_CODEC_AC3, WAVE_FORMAT_DOLBY_AC3_SPDIF}, /**< AC-3 padded for S/PDIF */
|
||||
{VC_CONTAINER_CODEC_AC3, WAVE_FORMAT_RAW_SPORT}, /**< AC-3 padded for S/PDIF */
|
||||
{VC_CONTAINER_CODEC_AC3, WAVE_FORMAT_ESST_AC3}, /**< AC-3 padded for S/PDIF */
|
||||
{VC_CONTAINER_CODEC_EAC3, WAVE_FORMAT_DVM},
|
||||
{VC_CONTAINER_CODEC_DTS, WAVE_FORMAT_DTS},
|
||||
#if 0
|
||||
{CODEC_G726, WAVE_FORMAT_G726_ADPCM},
|
||||
{CODEC_G726, WAVE_FORMAT_DF_G726},
|
||||
{CODEC_G726, WAVE_FORMAT_G726ADPCM},
|
||||
{CODEC_G726, WAVE_FORMAT_PANASONIC_G726},
|
||||
#endif
|
||||
{VC_CONTAINER_CODEC_MP4A, WAVE_FORMAT_AAC},
|
||||
{VC_CONTAINER_CODEC_MP4A, WAVE_FORMAT_MP4A},
|
||||
{VC_CONTAINER_CODEC_ATRAC3, WAVE_FORMAT_SONY_SCX},
|
||||
{VC_CONTAINER_CODEC_UNKNOWN, WAVE_FORMAT_UNKNOWN}
|
||||
};
|
||||
|
||||
VC_CONTAINER_FOURCC_T waveformat_to_codec(uint16_t waveformat_id)
|
||||
{
|
||||
unsigned int i;
|
||||
for(i = 0; codec_to_wf_table[i].codec != VC_CONTAINER_CODEC_UNKNOWN; i++)
|
||||
if(codec_to_wf_table[i].id == waveformat_id) break;
|
||||
return codec_to_wf_table[i].codec;
|
||||
}
|
||||
|
||||
uint16_t codec_to_waveformat(VC_CONTAINER_FOURCC_T codec)
|
||||
{
|
||||
unsigned int i;
|
||||
for(i = 0; codec_to_wf_table[i].codec != VC_CONTAINER_CODEC_UNKNOWN; i++)
|
||||
if(codec_to_wf_table[i].codec == codec) break;
|
||||
return codec_to_wf_table[i].id;
|
||||
}
|
||||
|
||||
static struct {
|
||||
VC_CONTAINER_FOURCC_T codec;
|
||||
uint32_t fourcc;
|
||||
} codec_to_vfw_table[] =
|
||||
{
|
||||
#if defined(ENABLE_CONTAINERS_STANDALONE) || !defined(NDEBUG)
|
||||
/* We are legally required to not play DivX in RELEASE mode. See Jira SW-3138 */
|
||||
{VC_CONTAINER_CODEC_DIV3, VC_FOURCC('D','I','V','3')},
|
||||
{VC_CONTAINER_CODEC_DIV3, VC_FOURCC('d','i','v','3')},
|
||||
{VC_CONTAINER_CODEC_DIV4, VC_FOURCC('D','I','V','4')},
|
||||
{VC_CONTAINER_CODEC_DIV4, VC_FOURCC('d','i','v','4')},
|
||||
{VC_CONTAINER_CODEC_MP4V, VC_FOURCC('D','X','5','0')},
|
||||
{VC_CONTAINER_CODEC_MP4V, VC_FOURCC('D','I','V','X')},
|
||||
{VC_CONTAINER_CODEC_MP4V, VC_FOURCC('d','i','v','x')},
|
||||
#endif /* ENABLE_CONTAINERS_STANDALONE || !NDEBUG */
|
||||
{VC_CONTAINER_CODEC_MP4V, VC_FOURCC('M','P','4','V')},
|
||||
{VC_CONTAINER_CODEC_MP4V, VC_FOURCC('m','p','4','v')},
|
||||
{VC_CONTAINER_CODEC_MP4V, VC_FOURCC('M','P','4','S')},
|
||||
{VC_CONTAINER_CODEC_MP4V, VC_FOURCC('m','p','4','s')},
|
||||
{VC_CONTAINER_CODEC_MP4V, VC_FOURCC('M','4','S','2')},
|
||||
{VC_CONTAINER_CODEC_MP4V, VC_FOURCC('m','4','s','2')},
|
||||
{VC_CONTAINER_CODEC_MP4V, VC_FOURCC('F','M','P','4')},
|
||||
{VC_CONTAINER_CODEC_MP4V, VC_FOURCC('X','V','I','D')},
|
||||
{VC_CONTAINER_CODEC_MP4V, VC_FOURCC('x','v','i','d')},
|
||||
{VC_CONTAINER_CODEC_DIV3, VC_FOURCC('M','P','4','3')},
|
||||
{VC_CONTAINER_CODEC_DIV3, VC_FOURCC('m','p','4','3')},
|
||||
{VC_CONTAINER_CODEC_MP1V, VC_FOURCC('m','p','g','1')},
|
||||
{VC_CONTAINER_CODEC_MP1V, VC_FOURCC('M','P','G','1')},
|
||||
{VC_CONTAINER_CODEC_MP2V, VC_FOURCC('m','p','g','2')},
|
||||
{VC_CONTAINER_CODEC_MP2V, VC_FOURCC('M','P','G','2')},
|
||||
{VC_CONTAINER_CODEC_MJPEG, VC_FOURCC('M','J','P','G')},
|
||||
{VC_CONTAINER_CODEC_MJPEG, VC_FOURCC('m','j','p','g')},
|
||||
{VC_CONTAINER_CODEC_WMV1, VC_FOURCC('W','M','V','1')},
|
||||
{VC_CONTAINER_CODEC_WMV1, VC_FOURCC('w','m','v','1')},
|
||||
{VC_CONTAINER_CODEC_WMV2, VC_FOURCC('W','M','V','2')},
|
||||
{VC_CONTAINER_CODEC_WMV2, VC_FOURCC('w','m','v','2')},
|
||||
{VC_CONTAINER_CODEC_WMV3, VC_FOURCC('W','M','V','3')},
|
||||
{VC_CONTAINER_CODEC_WMV3, VC_FOURCC('w','m','v','3')},
|
||||
{VC_CONTAINER_CODEC_WVC1, VC_FOURCC('W','V','C','1')},
|
||||
{VC_CONTAINER_CODEC_WVC1, VC_FOURCC('w','v','c','1')},
|
||||
{VC_CONTAINER_CODEC_WMVA, VC_FOURCC('w','m','v','a')},
|
||||
{VC_CONTAINER_CODEC_WMVA, VC_FOURCC('W','M','V','A')},
|
||||
{VC_CONTAINER_CODEC_VP6, VC_FOURCC('V','P','6','F')},
|
||||
{VC_CONTAINER_CODEC_VP6, VC_FOURCC('v','p','6','f')},
|
||||
{VC_CONTAINER_CODEC_VP7, VC_FOURCC('V','P','7','0')},
|
||||
{VC_CONTAINER_CODEC_VP7, VC_FOURCC('v','p','7','0')},
|
||||
{VC_CONTAINER_CODEC_H263, VC_FOURCC('H','2','6','3')},
|
||||
{VC_CONTAINER_CODEC_H263, VC_FOURCC('h','2','6','3')},
|
||||
{VC_CONTAINER_CODEC_H264, VC_FOURCC('H','2','6','4')},
|
||||
{VC_CONTAINER_CODEC_H264, VC_FOURCC('h','2','6','4')},
|
||||
{VC_CONTAINER_CODEC_H264, VC_FOURCC('A','V','C','1')},
|
||||
{VC_CONTAINER_CODEC_H264, VC_FOURCC('a','v','c','1')},
|
||||
{VC_CONTAINER_CODEC_SPARK, VC_FOURCC('F','L','V','1')},
|
||||
{VC_CONTAINER_CODEC_SPARK, VC_FOURCC('f','l','v','1')},
|
||||
{VC_CONTAINER_CODEC_UNKNOWN, 0}
|
||||
};
|
||||
|
||||
VC_CONTAINER_FOURCC_T vfw_fourcc_to_codec(uint32_t fourcc)
|
||||
{
|
||||
unsigned int i;
|
||||
for(i = 0; codec_to_vfw_table[i].codec != VC_CONTAINER_CODEC_UNKNOWN; i++)
|
||||
if(codec_to_vfw_table[i].fourcc == fourcc) break;
|
||||
|
||||
if(codec_to_vfw_table[i].codec == VC_CONTAINER_CODEC_UNKNOWN)
|
||||
return fourcc;
|
||||
|
||||
return codec_to_vfw_table[i].codec;
|
||||
}
|
||||
|
||||
uint32_t codec_to_vfw_fourcc(VC_CONTAINER_FOURCC_T codec)
|
||||
{
|
||||
unsigned int i;
|
||||
for(i = 0; codec_to_vfw_table[i].codec != VC_CONTAINER_CODEC_UNKNOWN; i++)
|
||||
if(codec_to_vfw_table[i].codec == codec) break;
|
||||
|
||||
return codec_to_vfw_table[i].fourcc;
|
||||
}
|
||||
|
||||
static struct {
|
||||
VC_CONTAINER_FOURCC_T codec;
|
||||
uint32_t fourcc;
|
||||
} codec_to_fourcc_table[] =
|
||||
{
|
||||
{VC_CONTAINER_CODEC_MP4V, VC_FOURCC('M','P','4','S')},
|
||||
{VC_CONTAINER_CODEC_MP4V, VC_FOURCC('M','4','S','2')},
|
||||
{VC_CONTAINER_CODEC_MP4V, VC_FOURCC('m','p','4','s')},
|
||||
{VC_CONTAINER_CODEC_MP4V, VC_FOURCC('m','4','s','2')},
|
||||
{VC_CONTAINER_CODEC_MP4V, VC_FOURCC('M','P','4','V')},
|
||||
{VC_CONTAINER_CODEC_MP4V, VC_FOURCC('m','p','4','v')},
|
||||
{VC_CONTAINER_CODEC_MP4V, VC_FOURCC('F','M','P','4')},
|
||||
{VC_CONTAINER_CODEC_DIV3, VC_FOURCC('M','P','4','3')},
|
||||
{VC_CONTAINER_CODEC_DIV3, VC_FOURCC('m','p','4','3')},
|
||||
{VC_CONTAINER_CODEC_WMV1, VC_FOURCC('W','M','V','1')},
|
||||
{VC_CONTAINER_CODEC_WMV1, VC_FOURCC('w','m','v','1')},
|
||||
{VC_CONTAINER_CODEC_WMV2, VC_FOURCC('W','M','V','2')},
|
||||
{VC_CONTAINER_CODEC_WMV2, VC_FOURCC('w','m','v','2')},
|
||||
{VC_CONTAINER_CODEC_WMV3, VC_FOURCC('W','M','V','3')},
|
||||
{VC_CONTAINER_CODEC_WMV3, VC_FOURCC('w','m','v','3')},
|
||||
{VC_CONTAINER_CODEC_MP1V, VC_FOURCC('m','p','g','1')},
|
||||
{VC_CONTAINER_CODEC_MP1V, VC_FOURCC('M','P','G','1')},
|
||||
{VC_CONTAINER_CODEC_MP2V, VC_FOURCC('m','p','g','2')},
|
||||
{VC_CONTAINER_CODEC_MP2V, VC_FOURCC('M','P','G','2')},
|
||||
{VC_CONTAINER_CODEC_MJPEG, VC_FOURCC('M','J','P','G')},
|
||||
{VC_CONTAINER_CODEC_MJPEG, VC_FOURCC('m','j','p','g')},
|
||||
{VC_CONTAINER_CODEC_UNKNOWN, 0}
|
||||
};
|
||||
|
||||
VC_CONTAINER_FOURCC_T fourcc_to_codec(uint32_t fourcc)
|
||||
{
|
||||
unsigned int i;
|
||||
for(i = 0; codec_to_fourcc_table[i].codec != VC_CONTAINER_CODEC_UNKNOWN; i++)
|
||||
if(codec_to_fourcc_table[i].fourcc == fourcc) break;
|
||||
|
||||
return codec_to_fourcc_table[i].codec;
|
||||
}
|
||||
|
||||
uint32_t codec_to_fourcc(VC_CONTAINER_FOURCC_T codec)
|
||||
{
|
||||
unsigned int i;
|
||||
for(i = 0; codec_to_fourcc_table[i].codec != VC_CONTAINER_CODEC_UNKNOWN; i++)
|
||||
if(codec_to_fourcc_table[i].codec == codec) break;
|
||||
|
||||
return codec_to_fourcc_table[i].fourcc;
|
||||
}
|
73
gfx/include/userland/containers/core/containers_common.h
Normal file
73
gfx/include/userland/containers/core/containers_common.h
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef VC_CONTAINERS_COMMON_H
|
||||
#define VC_CONTAINERS_COMMON_H
|
||||
|
||||
/** \file containers_common.h
|
||||
* Common definitions for containers infrastructure
|
||||
*/
|
||||
|
||||
#ifndef ENABLE_CONTAINERS_STANDALONE
|
||||
# include "vcos.h"
|
||||
# define vc_container_assert(a) vcos_assert(a)
|
||||
#else
|
||||
# include "assert.h"
|
||||
# define vc_container_assert(a) assert(a)
|
||||
#endif /* ENABLE_CONTAINERS_STANDALONE */
|
||||
|
||||
#ifndef countof
|
||||
# define countof(a) (sizeof(a) / sizeof(a[0]))
|
||||
#endif
|
||||
|
||||
#ifndef MIN
|
||||
# define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
#endif
|
||||
#ifndef MAX
|
||||
# define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# define strcasecmp stricmp
|
||||
# define strncasecmp strnicmp
|
||||
#endif
|
||||
|
||||
#define STATIC_INLINE static __inline
|
||||
#define VC_CONTAINER_PARAM_UNUSED(a) (void)(a)
|
||||
|
||||
#if defined(__HIGHC__) && !defined(strcasecmp)
|
||||
# define strcasecmp(a,b) _stricmp(a,b)
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) && (__GNUC__ > 2)
|
||||
# define VC_CONTAINER_CONSTRUCTOR(func) void __attribute__((constructor,used)) func(void)
|
||||
# define VC_CONTAINER_DESTRUCTOR(func) void __attribute__((destructor,used)) func(void)
|
||||
#else
|
||||
# define VC_CONTAINER_CONSTRUCTOR(func) void func(void)
|
||||
# define VC_CONTAINER_DESTRUCTOR(func) void func(void)
|
||||
#endif
|
||||
|
||||
#endif /* VC_CONTAINERS_COMMON_H */
|
222
gfx/include/userland/containers/core/containers_filters.c
Normal file
222
gfx/include/userland/containers/core/containers_filters.c
Normal file
@ -0,0 +1,222 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "containers/containers.h"
|
||||
#include "containers/core/containers_private.h"
|
||||
#include "containers/core/containers_filters.h"
|
||||
|
||||
#if !defined(ENABLE_CONTAINERS_STANDALONE)
|
||||
#include "vcos_dlfcn.h"
|
||||
#define DL_SUFFIX VCOS_SO_EXT
|
||||
#ifndef DL_PATH_PREFIX
|
||||
#define DL_PATH_PREFIX ""
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef struct VC_CONTAINER_FILTER_PRIVATE_T
|
||||
{
|
||||
/** Pointer to the container filter code and symbols */
|
||||
void *handle;
|
||||
} VC_CONTAINER_FILTER_PRIVATE_T;
|
||||
|
||||
typedef VC_CONTAINER_STATUS_T (*VC_CONTAINER_FILTER_OPEN_FUNC_T)(VC_CONTAINER_FILTER_T*, VC_CONTAINER_FOURCC_T);
|
||||
|
||||
static VC_CONTAINER_FILTER_OPEN_FUNC_T load_library(void **handle, VC_CONTAINER_FOURCC_T filter, const char *name);
|
||||
static void unload_library(void *handle);
|
||||
|
||||
static struct {
|
||||
VC_CONTAINER_FOURCC_T filter;
|
||||
const char *name;
|
||||
} filter_to_name_table[] =
|
||||
{
|
||||
{VC_FOURCC('d','r','m',' '), "divx"},
|
||||
{VC_FOURCC('d','r','m',' '), "hdcp2"},
|
||||
{0, NULL}
|
||||
};
|
||||
|
||||
static VC_CONTAINER_STATUS_T vc_container_filter_load(VC_CONTAINER_FILTER_T *p_ctx,
|
||||
VC_CONTAINER_FOURCC_T filter,
|
||||
VC_CONTAINER_FOURCC_T type)
|
||||
{
|
||||
void *handle = NULL;
|
||||
VC_CONTAINER_FILTER_OPEN_FUNC_T func;
|
||||
VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
unsigned int i;
|
||||
|
||||
for(i = 0; filter_to_name_table[i].filter; ++i)
|
||||
{
|
||||
if (filter_to_name_table[i].filter == filter)
|
||||
{
|
||||
if ((func = load_library(&handle, filter, filter_to_name_table[i].name)) != NULL)
|
||||
{
|
||||
status = (*func)(p_ctx, type);
|
||||
if(status == VC_CONTAINER_SUCCESS) break;
|
||||
unload_library(handle);
|
||||
if (status != VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
p_ctx->priv->handle = handle;
|
||||
return status;
|
||||
}
|
||||
|
||||
static void vc_container_filter_unload(VC_CONTAINER_FILTER_T *p_ctx)
|
||||
{
|
||||
unload_library(p_ctx->priv->handle);
|
||||
p_ctx->priv->handle = NULL;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_CONTAINER_FILTER_T *vc_container_filter_open(VC_CONTAINER_FOURCC_T filter,
|
||||
VC_CONTAINER_FOURCC_T type,
|
||||
VC_CONTAINER_T *p_container,
|
||||
VC_CONTAINER_STATUS_T *p_status )
|
||||
{
|
||||
VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_NOT_FOUND;
|
||||
VC_CONTAINER_FILTER_T *p_ctx = 0;
|
||||
VC_CONTAINER_FILTER_PRIVATE_T *priv = 0;
|
||||
|
||||
/* Allocate our context before trying out the different filter modules */
|
||||
p_ctx = malloc(sizeof(*p_ctx) + sizeof(*priv));
|
||||
if(!p_ctx) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
|
||||
memset(p_ctx, 0, sizeof(*p_ctx) + sizeof(*priv));
|
||||
p_ctx->priv = priv = (VC_CONTAINER_FILTER_PRIVATE_T *)&p_ctx[1];
|
||||
p_ctx->container = p_container;
|
||||
|
||||
status = vc_container_filter_load(p_ctx, filter, type);
|
||||
if(status != VC_CONTAINER_SUCCESS) goto error;
|
||||
|
||||
end:
|
||||
if(p_status) *p_status = status;
|
||||
return p_ctx;
|
||||
|
||||
error:
|
||||
if(p_ctx) free(p_ctx);
|
||||
p_ctx = 0;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_CONTAINER_STATUS_T vc_container_filter_close( VC_CONTAINER_FILTER_T *p_ctx )
|
||||
{
|
||||
if (p_ctx)
|
||||
{
|
||||
if(p_ctx->pf_close) p_ctx->pf_close(p_ctx);
|
||||
if(p_ctx->priv && p_ctx->priv->handle) vc_container_filter_unload(p_ctx);
|
||||
free(p_ctx);
|
||||
}
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_CONTAINER_STATUS_T vc_container_filter_process( VC_CONTAINER_FILTER_T *p_ctx, VC_CONTAINER_PACKET_T *p_packet )
|
||||
{
|
||||
VC_CONTAINER_STATUS_T status;
|
||||
status = p_ctx->pf_process(p_ctx, p_packet);
|
||||
return status;
|
||||
}
|
||||
|
||||
VC_CONTAINER_STATUS_T vc_container_filter_control(VC_CONTAINER_FILTER_T *p_ctx, VC_CONTAINER_CONTROL_T operation, ... )
|
||||
{
|
||||
VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
|
||||
va_list args;
|
||||
|
||||
va_start( args, operation );
|
||||
if(p_ctx->pf_control)
|
||||
status = p_ctx->pf_control(p_ctx, operation, args);
|
||||
va_end( args );
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static VC_CONTAINER_FILTER_OPEN_FUNC_T load_library(void **handle, VC_CONTAINER_FOURCC_T filter, const char *name)
|
||||
{
|
||||
VC_CONTAINER_FILTER_OPEN_FUNC_T func = NULL;
|
||||
#ifdef ENABLE_CONTAINERS_STANDALONE
|
||||
VC_CONTAINER_PARAM_UNUSED(handle);
|
||||
VC_CONTAINER_PARAM_UNUSED(filter);
|
||||
VC_CONTAINER_PARAM_UNUSED(name);
|
||||
#else
|
||||
char *dl_name, *entrypt_name;
|
||||
const char *entrypt_name_short = "filter_open";
|
||||
char filter_[6], *ptr;
|
||||
void *dl_handle;
|
||||
int dl_name_len;
|
||||
int entrypt_name_len;
|
||||
|
||||
snprintf(filter_, sizeof(filter_), "%4.4s", (const char*)&filter);
|
||||
ptr = strchr(filter_, '\0');
|
||||
while (ptr > filter_ && isspace(*--ptr)) *ptr = '\0';
|
||||
strncat(filter_, "_", 1);
|
||||
|
||||
dl_name_len = strlen(DL_PATH_PREFIX) + strlen(filter_) + strlen(name) + strlen(DL_SUFFIX) + 1;
|
||||
dl_name = malloc(dl_name_len);
|
||||
if (!dl_name) return NULL;
|
||||
|
||||
entrypt_name_len = strlen(name) + 1 + strlen(filter_) + strlen(entrypt_name_short) + 1;
|
||||
entrypt_name = malloc(entrypt_name_len);
|
||||
if (!entrypt_name)
|
||||
{
|
||||
free(dl_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
snprintf(dl_name, dl_name_len, "%s%s%s%s", DL_PATH_PREFIX, filter_, name, DL_SUFFIX);
|
||||
snprintf(entrypt_name, entrypt_name_len, "%s_%s%s", name, filter_, entrypt_name_short);
|
||||
|
||||
if ((dl_handle = vcos_dlopen(dl_name, VCOS_DL_NOW)) != NULL)
|
||||
{
|
||||
/* Try generic entrypoint name before the mangled, full name */
|
||||
func = (VC_CONTAINER_FILTER_OPEN_FUNC_T)vcos_dlsym(dl_handle, entrypt_name_short);
|
||||
if (!func) func = (VC_CONTAINER_FILTER_OPEN_FUNC_T)vcos_dlsym(dl_handle, entrypt_name);
|
||||
/* Only return handle if symbol found */
|
||||
if (func)
|
||||
*handle = dl_handle;
|
||||
else
|
||||
vcos_dlclose(dl_handle);
|
||||
}
|
||||
|
||||
free(dl_name);
|
||||
free(entrypt_name);
|
||||
#endif
|
||||
return func;
|
||||
}
|
||||
|
||||
static void unload_library(void *handle)
|
||||
{
|
||||
#ifdef ENABLE_CONTAINERS_STANDALONE
|
||||
VC_CONTAINER_PARAM_UNUSED(handle);
|
||||
#else
|
||||
vcos_dlclose(handle);
|
||||
#endif
|
||||
}
|
110
gfx/include/userland/containers/core/containers_filters.h
Normal file
110
gfx/include/userland/containers/core/containers_filters.h
Normal file
@ -0,0 +1,110 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef VC_CONTAINERS_FILTERS_H
|
||||
#define VC_CONTAINERS_FILTERS_H
|
||||
|
||||
/** \file containers_filters.h
|
||||
* Interface definition for the filter abstraction used by the container
|
||||
* common layer */
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "containers/containers.h"
|
||||
|
||||
/** \defgroup VcContainerFilterApi Container Filter API */
|
||||
/* @{ */
|
||||
|
||||
/** Container Filter Context.
|
||||
* This structure defines the context for a container filter instance */
|
||||
typedef struct VC_CONTAINER_FILTER_T
|
||||
{
|
||||
/** Pointer to container instance */
|
||||
struct VC_CONTAINER_T *container;
|
||||
/** Pointer to information private to the container filter instance */
|
||||
struct VC_CONTAINER_FILTER_PRIVATE_T *priv;
|
||||
/** Pointer to information private to the container filter module */
|
||||
struct VC_CONTAINER_FILTER_MODULE_T *module;
|
||||
|
||||
/** \note the following list of function pointers should not be used directly.
|
||||
* They defines the interface for implementing container filter modules and are
|
||||
* filled in by the container filter modules themselves. */
|
||||
|
||||
/** \private
|
||||
* Function pointer to close and free all resources allocated by a
|
||||
* container filter module */
|
||||
VC_CONTAINER_STATUS_T (*pf_close)(struct VC_CONTAINER_FILTER_T *filter);
|
||||
|
||||
/** \private
|
||||
* Function pointer to filter a data packet using a container filter module */
|
||||
VC_CONTAINER_STATUS_T (*pf_process)(struct VC_CONTAINER_FILTER_T *filter, VC_CONTAINER_PACKET_T *p_packet);
|
||||
|
||||
/** \private
|
||||
* Function pointer to control container filter module */
|
||||
VC_CONTAINER_STATUS_T (*pf_control)( struct VC_CONTAINER_FILTER_T *filter, VC_CONTAINER_CONTROL_T operation, va_list args );
|
||||
|
||||
} VC_CONTAINER_FILTER_T;
|
||||
|
||||
/** Opens a container filter using a four character code describing the filter.
|
||||
* This will create an instance of the container filter.
|
||||
*
|
||||
* \param filter Four Character Code describing the filter
|
||||
* \param type Four Character Code describing the subtype - indicated whether filter is encrypt or decrypt
|
||||
* \param container Pointer to the container instance
|
||||
* \param status Returns the status of the operation
|
||||
* \return If successful, this returns a pointer to the new instance
|
||||
* of the container filter. Returns NULL on failure.
|
||||
*/
|
||||
VC_CONTAINER_FILTER_T *vc_container_filter_open(VC_CONTAINER_FOURCC_T filter,
|
||||
VC_CONTAINER_FOURCC_T type,
|
||||
VC_CONTAINER_T *container,
|
||||
VC_CONTAINER_STATUS_T *status );
|
||||
|
||||
/** Closes an instance of a container filter.
|
||||
* \param context Pointer to the VC_CONTAINER_FILTER_T context of the instance to close
|
||||
* \return VC_CONTAINER_SUCCESS on success.
|
||||
*/
|
||||
VC_CONTAINER_STATUS_T vc_container_filter_close( VC_CONTAINER_FILTER_T *context );
|
||||
|
||||
/** Filter a data packet using a container filter module.
|
||||
* \param context Pointer to the VC_CONTAINER_FILTER_T instance to use
|
||||
* \param packet Pointer to the VC_CONTAINER_PACKET_T structure to process
|
||||
* \return the status of the operation
|
||||
*/
|
||||
VC_CONTAINER_STATUS_T vc_container_filter_process(VC_CONTAINER_FILTER_T *context, VC_CONTAINER_PACKET_T *p_packet);
|
||||
|
||||
/** Extensible control function for container filter modules.
|
||||
* This function takes a variable number of arguments which will depend on the specific operation.
|
||||
*
|
||||
* \param context Pointer to the VC_CONTAINER_FILTER_T instance to use
|
||||
* \param operation The requested operation
|
||||
* \param args Arguments for the operation
|
||||
* \return the status of the operation
|
||||
*/
|
||||
VC_CONTAINER_STATUS_T vc_container_filter_control(VC_CONTAINER_FILTER_T *context, VC_CONTAINER_CONTROL_T operation, ... );
|
||||
|
||||
/* @} */
|
||||
|
||||
#endif /* VC_CONTAINERS_FILTERS_H */
|
192
gfx/include/userland/containers/core/containers_index.c
Normal file
192
gfx/include/userland/containers/core/containers_index.c
Normal file
@ -0,0 +1,192 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "containers/containers.h"
|
||||
#include "containers/core/containers_index.h"
|
||||
|
||||
typedef struct {
|
||||
int64_t file_offset;
|
||||
int64_t time;
|
||||
} VC_CONTAINER_INDEX_POS_T;
|
||||
|
||||
struct VC_CONTAINER_INDEX_T {
|
||||
int len; // log2 of length of entry array
|
||||
int next; // next array entry to write into
|
||||
int gap; // log2 of the passes through entry array to build the full list
|
||||
int mgap; // len-gap, stored for convenience
|
||||
int count; // number of calls to index_add since last entry added
|
||||
int max_count; // log2 of the number of calls to discard between each entry added
|
||||
int64_t max_time; // time of the latest entry
|
||||
VC_CONTAINER_INDEX_POS_T entry[0]; // array of position/time pairs
|
||||
};
|
||||
|
||||
// We have a fixed length list, and when it is full we want to discard half the entries.
|
||||
// This is done without coping data by mapping the entry number to the index to the array,
|
||||
// in the following way:
|
||||
// Length is a power of two, so the entry number is a fixed constant bit width. The highest gap
|
||||
// bits are used as a direct offset into the array (o), the lowest mgap bits are right shifted by
|
||||
// gap to increment this (S). Each time we double the number of passes through the actual array.
|
||||
// So if len=3, we start off with mgap=3, gap=0, we have a single pass with the trivial mapping:
|
||||
// |S|S|S| [0 1 2 3 4 5 6 7]
|
||||
// when this is full we change to mgap=2, gap=1, so we iterate this way:
|
||||
// |o|S|S| [0 2 4 6] [1 3 5 7]
|
||||
// when this is full we change to mgap=1, gap=2
|
||||
// |o|o|S| [0 4] [1 5] [2 6] [3 7]
|
||||
// when this is full we change to this, which is equivalent to where we started
|
||||
// |o|o|o| [0] [1] [2] [3] [4] [5] [6] [7]
|
||||
|
||||
#define ENTRY(x, i) ((x)->gap == 0 ? (i) : ((i)>>(x)->mgap) + (((i) & ((1<<(x)->mgap)-1)) << (x)->gap))
|
||||
|
||||
VC_CONTAINER_STATUS_T vc_container_index_create( VC_CONTAINER_INDEX_T **index, int length )
|
||||
{
|
||||
VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_OUT_OF_MEMORY;
|
||||
VC_CONTAINER_INDEX_T *id = NULL;
|
||||
int len = 0;
|
||||
|
||||
if(length < 16) length = 16;
|
||||
if(length > 4096) length = 4096;
|
||||
while((length >>= 1) != 0)
|
||||
len++;
|
||||
|
||||
id = malloc(sizeof(VC_CONTAINER_INDEX_T) + (sizeof(VC_CONTAINER_INDEX_POS_T)<<len));
|
||||
if(id == NULL) { goto error; }
|
||||
|
||||
memset(id, 0, sizeof(VC_CONTAINER_INDEX_T));
|
||||
|
||||
id->len = id->mgap = len;
|
||||
|
||||
*index = id;
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
|
||||
error:
|
||||
return status;
|
||||
}
|
||||
|
||||
VC_CONTAINER_STATUS_T vc_container_index_free( VC_CONTAINER_INDEX_T *index )
|
||||
{
|
||||
if(index == NULL)
|
||||
return VC_CONTAINER_ERROR_FAILED;
|
||||
|
||||
free(index);
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
VC_CONTAINER_STATUS_T vc_container_index_add( VC_CONTAINER_INDEX_T *index, int64_t time, int64_t file_offset )
|
||||
{
|
||||
if(index == NULL)
|
||||
return VC_CONTAINER_ERROR_FAILED;
|
||||
|
||||
// reject entries if they are in part of the time covered
|
||||
if(index->next != 0 && time <= index->max_time)
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
|
||||
index->count++;
|
||||
if(index->count == (1<<index->max_count))
|
||||
{
|
||||
int entry;
|
||||
if(index->next == (1<<index->len))
|
||||
{
|
||||
// New entry doesn't fit, we discard every other index record
|
||||
// by changing how we map index positions to array entry indexes.
|
||||
index->next >>= 1;
|
||||
index->gap++;
|
||||
index->mgap--;
|
||||
index->max_count++;
|
||||
|
||||
if(index->gap == index->len)
|
||||
{
|
||||
index->gap = 0;
|
||||
index->mgap = index->len;
|
||||
}
|
||||
}
|
||||
|
||||
entry = ENTRY(index, index->next);
|
||||
|
||||
index->entry[entry].file_offset = file_offset;
|
||||
index->entry[entry].time = time;
|
||||
index->count = 0;
|
||||
index->next++;
|
||||
index->max_time = time;
|
||||
}
|
||||
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
VC_CONTAINER_STATUS_T vc_container_index_get( VC_CONTAINER_INDEX_T *index, int later, int64_t *time, int64_t *file_offset, int *past )
|
||||
{
|
||||
int guess, start, end, entry;
|
||||
|
||||
if(index == NULL || index->next == 0)
|
||||
return VC_CONTAINER_ERROR_FAILED;
|
||||
|
||||
guess = start = 0;
|
||||
end = index->next-1;
|
||||
|
||||
*past = *time > index->max_time;
|
||||
|
||||
while(end-start > 1)
|
||||
{
|
||||
int64_t gtime;
|
||||
guess = (start+end)>>1;
|
||||
gtime = index->entry[ENTRY(index, guess)].time;
|
||||
|
||||
if(*time < gtime)
|
||||
end = guess;
|
||||
else if(*time > gtime)
|
||||
start = guess;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (*time != index->entry[ENTRY(index, guess)].time)
|
||||
{
|
||||
if(later)
|
||||
{
|
||||
if(*time <= index->entry[ENTRY(index, start)].time)
|
||||
guess = start;
|
||||
else
|
||||
guess = end;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(*time >= index->entry[ENTRY(index, end)].time)
|
||||
guess = end;
|
||||
else
|
||||
guess = start;
|
||||
}
|
||||
}
|
||||
|
||||
entry = ENTRY(index, guess);
|
||||
*time = index->entry[entry].time;
|
||||
*file_offset = index->entry[entry].file_offset;
|
||||
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
82
gfx/include/userland/containers/core/containers_index.h
Normal file
82
gfx/include/userland/containers/core/containers_index.h
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef VC_CONTAINERS_INDEX_H
|
||||
#define VC_CONTAINERS_INDEX_H
|
||||
|
||||
/** \file containers_index.h
|
||||
* Definition of index utilitie for containers. Creates and maintains an
|
||||
* index of file offsets and times, and is able to suggest a file position
|
||||
* to seek to achieve a given time target. Useful for container formats
|
||||
* that don't include an index.
|
||||
*/
|
||||
|
||||
#include "containers/containers.h"
|
||||
|
||||
struct VC_CONTAINER_INDEX_T;
|
||||
typedef struct VC_CONTAINER_INDEX_T VC_CONTAINER_INDEX_T;
|
||||
|
||||
/**
|
||||
* Creates an index with a suggested number of entries.
|
||||
* @param index Pointer to created index will be filled here on success.
|
||||
* @param length Suggested length of index.
|
||||
* @return Status code
|
||||
*/
|
||||
VC_CONTAINER_STATUS_T vc_container_index_create( VC_CONTAINER_INDEX_T **index, int length );
|
||||
|
||||
|
||||
/**
|
||||
* Frees an index.
|
||||
* @param index Pointer to valid index.
|
||||
* @return Status code.
|
||||
*/
|
||||
VC_CONTAINER_STATUS_T vc_container_index_free( VC_CONTAINER_INDEX_T *index );
|
||||
|
||||
|
||||
/**
|
||||
* Adds an entry to the index. If the index is full then some stored records will be
|
||||
* discarded.
|
||||
* @param index Pointer to a valid index.
|
||||
* @param time Timestamp of new index entry.
|
||||
* @param file_offset File offset for new index entry.
|
||||
* @return Status code
|
||||
*/
|
||||
VC_CONTAINER_STATUS_T vc_container_index_add( VC_CONTAINER_INDEX_T *index, int64_t time, int64_t file_offset );
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves the best entry for the supplied time offset.
|
||||
* @param index Pointer to valid index.
|
||||
* @param later If true, the selected entry is the earliest retained entry with a greater or equal timestamp.
|
||||
* If false, the selected entry is the latest retained entry with an earlier or equal timestamp.
|
||||
* @param time The requested time. On success, this is filled in with the time of the selected entry.
|
||||
* @param file_offset On success, this is filled in with the file offset of the selected entry.
|
||||
* @param past Set if the requested time is after the last entry in the index.
|
||||
* @return Status code.
|
||||
*/
|
||||
VC_CONTAINER_STATUS_T vc_container_index_get( VC_CONTAINER_INDEX_T *index, int later, int64_t *time, int64_t *file_offset, int *past );
|
||||
|
||||
#endif /* VC_CONTAINERS_WRITER_UTILS_H */
|
1088
gfx/include/userland/containers/core/containers_io.c
Normal file
1088
gfx/include/userland/containers/core/containers_io.c
Normal file
File diff suppressed because it is too large
Load Diff
229
gfx/include/userland/containers/core/containers_io.h
Normal file
229
gfx/include/userland/containers/core/containers_io.h
Normal file
@ -0,0 +1,229 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef VC_CONTAINERS_IO_H
|
||||
#define VC_CONTAINERS_IO_H
|
||||
|
||||
/** \file containers_io.h
|
||||
* Interface definition for the input / output abstraction layer used by container
|
||||
* readers and writers */
|
||||
#include "containers/containers.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** \defgroup VcContainerIoApi Container I/O API */
|
||||
/* @{ */
|
||||
|
||||
/** Container io opening mode.
|
||||
* This is used to specify whether a reader or writer is requested.
|
||||
*/
|
||||
typedef enum {
|
||||
VC_CONTAINER_IO_MODE_READ = 0, /**< Container io opened in reading mode */
|
||||
VC_CONTAINER_IO_MODE_WRITE = 1 /**< Container io opened in writing mode */
|
||||
} VC_CONTAINER_IO_MODE_T;
|
||||
|
||||
/** \name Container I/O Capabilities
|
||||
* The following flags are exported by container i/o modules to describe their capabilities */
|
||||
/* @{ */
|
||||
/** Type definition for container I/O capabilities */
|
||||
typedef uint32_t VC_CONTAINER_IO_CAPABILITIES_T;
|
||||
/** Seeking is not supported */
|
||||
#define VC_CONTAINER_IO_CAPS_CANT_SEEK 0x1
|
||||
/** Seeking is slow and should be avoided */
|
||||
#define VC_CONTAINER_IO_CAPS_SEEK_SLOW 0x2
|
||||
/** The I/O doesn't provide any caching of the data */
|
||||
#define VC_CONTAINER_IO_CAPS_NO_CACHING 0x4
|
||||
/* @} */
|
||||
|
||||
/** Container Input / Output Context.
|
||||
* This structure defines the context for a container io instance */
|
||||
struct VC_CONTAINER_IO_T
|
||||
{
|
||||
/** Pointer to information private to the container io instance */
|
||||
struct VC_CONTAINER_IO_PRIVATE_T *priv;
|
||||
|
||||
/** Pointer to information private to the container io module */
|
||||
struct VC_CONTAINER_IO_MODULE_T *module;
|
||||
|
||||
/** Uniform Resource Identifier for the stream to open.
|
||||
* This is a string encoded in UTF-8 which follows the syntax defined in
|
||||
* RFC2396 (http://tools.ietf.org/html/rfc2396). */
|
||||
char *uri;
|
||||
|
||||
/** Pre-parsed URI */
|
||||
struct VC_URI_PARTS_T *uri_parts;
|
||||
|
||||
/** Current offset into the i/o stream */
|
||||
int64_t offset;
|
||||
|
||||
/** Current size of the i/o stream (0 if unknown). This size might grow during the
|
||||
* lifetime of the i/o instance (for instance when doing progressive download). */
|
||||
int64_t size;
|
||||
|
||||
/** Capabilities of the i/o stream */
|
||||
VC_CONTAINER_IO_CAPABILITIES_T capabilities;
|
||||
|
||||
/** Status of the i/o stream */
|
||||
VC_CONTAINER_STATUS_T status;
|
||||
|
||||
/** Maximum size allowed for this i/o stream (0 if unknown). This is used during writing
|
||||
* to limit the size of the stream to below this value. */
|
||||
int64_t max_size;
|
||||
|
||||
/** \note the following list of function pointers should not be used directly.
|
||||
* They defines the interface for implementing container io modules and are filled in
|
||||
* by the container modules themselves. */
|
||||
|
||||
/** \private
|
||||
* Function pointer to close and free all resources allocated by a
|
||||
* container io module */
|
||||
VC_CONTAINER_STATUS_T (*pf_close)(struct VC_CONTAINER_IO_T *io);
|
||||
|
||||
/** \private
|
||||
* Function pointer to read or skip data from container io module */
|
||||
size_t (*pf_read)(struct VC_CONTAINER_IO_T *io, void *buffer, size_t size);
|
||||
|
||||
/** \private
|
||||
* Function pointer to write data to a container io module */
|
||||
size_t (*pf_write)(struct VC_CONTAINER_IO_T *io, const void *buffer, size_t size);
|
||||
|
||||
/** \private
|
||||
* Function pointer to seek into a container io module */
|
||||
VC_CONTAINER_STATUS_T (*pf_seek)(struct VC_CONTAINER_IO_T *io, int64_t offset);
|
||||
|
||||
/** \private
|
||||
* Function pointer to perform a control operation on a container io module */
|
||||
VC_CONTAINER_STATUS_T (*pf_control)(struct VC_CONTAINER_IO_T *io,
|
||||
VC_CONTAINER_CONTROL_T operation, va_list args);
|
||||
|
||||
};
|
||||
|
||||
/** Opens an i/o stream pointed to by a URI.
|
||||
* This will create an instance of the container i/o module.
|
||||
*
|
||||
* \param uri Uniform Resource Identifier pointing to the multimedia container
|
||||
* \param mode Mode in which the i/o stream will be opened
|
||||
* \param status Returns the status of the operation
|
||||
* \return If successful, this returns a pointer to the new instance
|
||||
* of the i/o module. Returns NULL on failure.
|
||||
*/
|
||||
VC_CONTAINER_IO_T *vc_container_io_open( const char *uri, VC_CONTAINER_IO_MODE_T mode,
|
||||
VC_CONTAINER_STATUS_T *status );
|
||||
|
||||
/** Creates an empty i/o stream. The i/o function pointers will have to be set
|
||||
* by the caller before the i/o gets used.
|
||||
* This will create an instance of the container i/o module.
|
||||
*
|
||||
* \param uri Uniform Resource Identifier pointing to the multimedia container
|
||||
* \param mode Mode in which the i/o stream will be opened
|
||||
* \param capabilities Flags indicating the capabilities of the i/o
|
||||
* \param status Returns the status of the operation
|
||||
* \return If successful, this returns a pointer to the new instance
|
||||
* of the i/o module. Returns NULL on failure.
|
||||
*/
|
||||
VC_CONTAINER_IO_T *vc_container_io_create( const char *uri, VC_CONTAINER_IO_MODE_T mode,
|
||||
VC_CONTAINER_IO_CAPABILITIES_T capabilities,
|
||||
VC_CONTAINER_STATUS_T *p_status );
|
||||
|
||||
/** Closes an instance of a container i/o module.
|
||||
* \param context Pointer to the VC_CONTAINER_IO_T context of the instance to close
|
||||
* \return VC_CONTAINER_SUCCESS on success.
|
||||
*/
|
||||
VC_CONTAINER_STATUS_T vc_container_io_close( VC_CONTAINER_IO_T *context );
|
||||
|
||||
/** Read data from an i/o stream without advancing the read position within the stream.
|
||||
* \param context Pointer to the VC_CONTAINER_IO_T instance to use
|
||||
* \param buffer Pointer to the buffer where the data will be read
|
||||
* \param size Number of bytes to read
|
||||
* \return The size of the data actually read.
|
||||
*/
|
||||
size_t vc_container_io_peek(VC_CONTAINER_IO_T *context, void *buffer, size_t size);
|
||||
|
||||
/** Read data from an i/o stream.
|
||||
* \param context Pointer to the VC_CONTAINER_IO_T instance to use
|
||||
* \param buffer Pointer to the buffer where the data will be read
|
||||
* \param size Number of bytes to read
|
||||
* \return The size of the data actually read.
|
||||
*/
|
||||
size_t vc_container_io_read(VC_CONTAINER_IO_T *context, void *buffer, size_t size);
|
||||
|
||||
/** Skip data in an i/o stream without reading it.
|
||||
* \param context Pointer to the VC_CONTAINER_IO_T instance to use
|
||||
* \param size Number of bytes to skip
|
||||
* \return The size of the data actually skipped.
|
||||
*/
|
||||
size_t vc_container_io_skip(VC_CONTAINER_IO_T *context, size_t size);
|
||||
|
||||
/** Write data to an i/o stream.
|
||||
* \param context Pointer to the VC_CONTAINER_IO_T instance to use
|
||||
* \param buffer Pointer to the buffer containing the data to write
|
||||
* \param size Number of bytes to write
|
||||
* \return The size of the data actually written.
|
||||
*/
|
||||
size_t vc_container_io_write(VC_CONTAINER_IO_T *context, const void *buffer, size_t size);
|
||||
|
||||
/** Seek into an i/o stream.
|
||||
* \param context Pointer to the VC_CONTAINER_IO_T instance to use
|
||||
* \param offset Absolute file offset to seek to
|
||||
* \return Status of the operation
|
||||
*/
|
||||
VC_CONTAINER_STATUS_T vc_container_io_seek(VC_CONTAINER_IO_T *context, int64_t offset);
|
||||
|
||||
/** Perform control operation on an i/o stream (va_list).
|
||||
* \param context Pointer to the VC_CONTAINER_IO_T instance to use
|
||||
* \param operation Control operation to be performed
|
||||
* \param args Additional arguments for the operation
|
||||
* \return Status of the operation
|
||||
*/
|
||||
VC_CONTAINER_STATUS_T vc_container_io_control_list(VC_CONTAINER_IO_T *context,
|
||||
VC_CONTAINER_CONTROL_T operation, va_list args);
|
||||
|
||||
/** Perform control operation on an i/o stream (varargs).
|
||||
* \param context Pointer to the VC_CONTAINER_IO_T instance to use
|
||||
* \param operation Control operation to be performed
|
||||
* \param ... Additional arguments for the operation
|
||||
* \return Status of the operation
|
||||
*/
|
||||
VC_CONTAINER_STATUS_T vc_container_io_control(VC_CONTAINER_IO_T *context,
|
||||
VC_CONTAINER_CONTROL_T operation, ...);
|
||||
|
||||
/** Cache the pointed region of the i/o stream (from current position).
|
||||
* This will allow future seeking into the specified region even on non-seekable streams.
|
||||
* \param context Pointer to the VC_CONTAINER_IO_T instance to use
|
||||
* \param size Size of the region to cache
|
||||
* \return Status of the operation
|
||||
*/
|
||||
size_t vc_container_io_cache(VC_CONTAINER_IO_T *context, size_t size);
|
||||
|
||||
/* @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* VC_CONTAINERS_HELPERS_H */
|
244
gfx/include/userland/containers/core/containers_io_helpers.c
Normal file
244
gfx/include/userland/containers/core/containers_io_helpers.c
Normal file
@ -0,0 +1,244 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include "containers/core/containers_private.h"
|
||||
#include "containers/core/containers_io_helpers.h"
|
||||
#include "containers/core/containers_logging.h"
|
||||
|
||||
void vc_container_helper_format_debug(VC_CONTAINER_T *ctx, int indent, const char *format, ...)
|
||||
{
|
||||
char debug_string[512];
|
||||
va_list args;
|
||||
int result;
|
||||
|
||||
if(indent >= (int)sizeof(debug_string)) return;
|
||||
memset(debug_string, ' ', indent);
|
||||
|
||||
va_start( args, format );
|
||||
result = vsnprintf(debug_string + indent, sizeof(debug_string) - indent, format, args);
|
||||
va_end( args );
|
||||
|
||||
if(result <= 0) return;
|
||||
|
||||
vc_container_log(ctx, VC_CONTAINER_LOG_FORMAT, debug_string);
|
||||
fflush(0);
|
||||
}
|
||||
|
||||
uint64_t vc_container_helper_int_debug(VC_CONTAINER_T *ctx, int type, uint64_t value, const char *name, int indent)
|
||||
{
|
||||
VC_CONTAINER_PARAM_UNUSED(ctx);
|
||||
|
||||
if(type == LOG_FORMAT_TYPE_HEX)
|
||||
vc_container_helper_format_debug(ctx, indent, "%s: 0x%"PRIx64, name, value);
|
||||
else
|
||||
vc_container_helper_format_debug(ctx, indent, "%s: %"PRIi64, name, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
uint64_t vc_container_helper_read_debug(VC_CONTAINER_T *ctx, int type, int size,
|
||||
const char *name, uint8_t *buffer, int indent, int b_skip)
|
||||
{
|
||||
int64_t offset = STREAM_POSITION(ctx);
|
||||
uint64_t value = 0;
|
||||
GUID_T guid;
|
||||
|
||||
if(type == LOG_FORMAT_TYPE_STRING ||
|
||||
type == LOG_FORMAT_TYPE_STRING_UTF16_LE ||
|
||||
type == LOG_FORMAT_TYPE_STRING_UTF16_BE)
|
||||
{
|
||||
uint8_t stringbuf[256];
|
||||
char utf8buf[256];
|
||||
int stringsize = sizeof(stringbuf) - 2;
|
||||
|
||||
if(!buffer)
|
||||
{
|
||||
buffer = stringbuf;
|
||||
if(size < stringsize) stringsize = size;
|
||||
}
|
||||
else stringsize = size;
|
||||
|
||||
value = vc_container_io_read(ctx->priv->io, buffer, stringsize);
|
||||
|
||||
if(!utf8_from_charset(type == LOG_FORMAT_TYPE_STRING ? "UTF8" : "UTF16-LE",
|
||||
utf8buf, sizeof(utf8buf), buffer, stringsize))
|
||||
vc_container_helper_format_debug(ctx, indent, "%s: \"%s\"", name, utf8buf);
|
||||
else
|
||||
vc_container_helper_format_debug(ctx, indent, "%s: (could not read)", name);
|
||||
|
||||
if(size - stringsize)
|
||||
value += vc_container_io_skip(ctx->priv->io, size - stringsize);
|
||||
return value;
|
||||
}
|
||||
|
||||
if(type == LOG_FORMAT_TYPE_UINT_LE)
|
||||
{
|
||||
switch(size)
|
||||
{
|
||||
case 1: value = vc_container_io_read_uint8(ctx->priv->io); break;
|
||||
case 2: value = vc_container_io_read_le_uint16(ctx->priv->io); break;
|
||||
case 3: value = vc_container_io_read_le_uint24(ctx->priv->io); break;
|
||||
case 4: value = vc_container_io_read_le_uint32(ctx->priv->io); break;
|
||||
case 5: value = vc_container_io_read_le_uint40(ctx->priv->io); break;
|
||||
case 6: value = vc_container_io_read_le_uint48(ctx->priv->io); break;
|
||||
case 7: value = vc_container_io_read_le_uint56(ctx->priv->io); break;
|
||||
case 8: value = vc_container_io_read_le_uint64(ctx->priv->io); break;
|
||||
}
|
||||
}
|
||||
else if(type == LOG_FORMAT_TYPE_UINT_BE)
|
||||
{
|
||||
switch(size)
|
||||
{
|
||||
case 1: value = vc_container_io_read_uint8(ctx->priv->io); break;
|
||||
case 2: value = vc_container_io_read_be_uint16(ctx->priv->io); break;
|
||||
case 3: value = vc_container_io_read_be_uint24(ctx->priv->io); break;
|
||||
case 4: value = vc_container_io_read_be_uint32(ctx->priv->io); break;
|
||||
case 5: value = vc_container_io_read_be_uint40(ctx->priv->io); break;
|
||||
case 6: value = vc_container_io_read_be_uint48(ctx->priv->io); break;
|
||||
case 7: value = vc_container_io_read_be_uint56(ctx->priv->io); break;
|
||||
case 8: value = vc_container_io_read_be_uint64(ctx->priv->io); break;
|
||||
}
|
||||
}
|
||||
else if(type == LOG_FORMAT_TYPE_FOURCC)
|
||||
{
|
||||
value = vc_container_io_read_fourcc(ctx->priv->io);
|
||||
}
|
||||
else if(type == LOG_FORMAT_TYPE_GUID)
|
||||
{
|
||||
value = vc_container_io_read(ctx->priv->io, &guid, 16);
|
||||
}
|
||||
else
|
||||
{
|
||||
vc_container_assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(type == LOG_FORMAT_TYPE_GUID)
|
||||
{
|
||||
if(value == 16)
|
||||
{
|
||||
vc_container_helper_format_debug(ctx, indent, "%s: 0x%x-0x%x-0x%x-0x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x",
|
||||
name, guid.word0, guid.short0, guid.short1,
|
||||
guid.bytes[0], guid.bytes[1], guid.bytes[2], guid.bytes[3],
|
||||
guid.bytes[4], guid.bytes[5], guid.bytes[6], guid.bytes[7]);
|
||||
if(buffer) memcpy(buffer, &guid, sizeof(guid));
|
||||
}
|
||||
}
|
||||
else if(type == LOG_FORMAT_TYPE_FOURCC)
|
||||
{
|
||||
uint32_t val = value;
|
||||
vc_container_helper_format_debug(ctx, indent, "%s: %4.4s", name, (char *)&val);
|
||||
}
|
||||
else
|
||||
{
|
||||
vc_container_helper_format_debug(ctx, indent, "%s: %"PRIi64, name, value);
|
||||
}
|
||||
|
||||
if(b_skip) value = (STREAM_POSITION(ctx) - offset) != size;
|
||||
return value;
|
||||
}
|
||||
|
||||
VC_CONTAINER_STATUS_T vc_container_helper_write_debug(VC_CONTAINER_T *ctx, int type, int size,
|
||||
const char *name, uint64_t value, const uint8_t *buffer, int indent, int silent)
|
||||
{
|
||||
VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
|
||||
|
||||
if(type == LOG_FORMAT_TYPE_STRING)
|
||||
{
|
||||
value = vc_container_io_write(ctx->priv->io, buffer, size);
|
||||
if(!silent)
|
||||
vc_container_helper_format_debug(ctx, indent, "%s: \"%ls\"", name, buffer);
|
||||
return value == (uint64_t)size ? VC_CONTAINER_SUCCESS : VC_CONTAINER_ERROR_FAILED;
|
||||
}
|
||||
|
||||
if(type == LOG_FORMAT_TYPE_UINT_LE)
|
||||
{
|
||||
switch(size)
|
||||
{
|
||||
case 1: status = vc_container_io_write_uint8(ctx->priv->io, (uint8_t)value); break;
|
||||
case 2: status = vc_container_io_write_le_uint16(ctx->priv->io, (uint16_t)value); break;
|
||||
case 3: status = vc_container_io_write_le_uint24(ctx->priv->io, (uint32_t)value); break;
|
||||
case 4: status = vc_container_io_write_le_uint32(ctx->priv->io, (uint32_t)value); break;
|
||||
case 8: status = vc_container_io_write_le_uint64(ctx->priv->io, value); break;
|
||||
}
|
||||
}
|
||||
else if(type == LOG_FORMAT_TYPE_UINT_BE)
|
||||
{
|
||||
switch(size)
|
||||
{
|
||||
case 1: status = vc_container_io_write_uint8(ctx->priv->io, (uint8_t)value); break;
|
||||
case 2: status = vc_container_io_write_be_uint16(ctx->priv->io, (uint16_t)value); break;
|
||||
case 3: status = vc_container_io_write_be_uint24(ctx->priv->io, (uint32_t)value); break;
|
||||
case 4: status = vc_container_io_write_be_uint32(ctx->priv->io, (uint32_t)value); break;
|
||||
case 8: status = vc_container_io_write_be_uint64(ctx->priv->io, value); break;
|
||||
}
|
||||
}
|
||||
else if(type == LOG_FORMAT_TYPE_FOURCC)
|
||||
{
|
||||
status = vc_container_io_write_fourcc(ctx->priv->io, (uint32_t)value);
|
||||
}
|
||||
else if(type == LOG_FORMAT_TYPE_GUID)
|
||||
{
|
||||
value = vc_container_io_write(ctx->priv->io, buffer, 16);
|
||||
}
|
||||
else
|
||||
{
|
||||
vc_container_assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(status)
|
||||
{
|
||||
vc_container_helper_format_debug(ctx, indent, "write failed for %s", name);
|
||||
return status;
|
||||
}
|
||||
|
||||
if(!silent)
|
||||
{
|
||||
if (type == LOG_FORMAT_TYPE_FOURCC)
|
||||
{
|
||||
vc_container_helper_format_debug(ctx, indent, "%s: %4.4s", name, (char *)&value);
|
||||
}
|
||||
else if(type == LOG_FORMAT_TYPE_GUID)
|
||||
{
|
||||
GUID_T guid;
|
||||
memcpy(&guid, buffer, sizeof(guid));
|
||||
vc_container_helper_format_debug(ctx, indent, "%s: 0x%x-0x%x-0x%x-0x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x",
|
||||
name, guid.word0, guid.short0, guid.short1,
|
||||
guid.bytes[0], guid.bytes[1], guid.bytes[2], guid.bytes[3],
|
||||
guid.bytes[4], guid.bytes[5], guid.bytes[6], guid.bytes[7]);
|
||||
}
|
||||
else
|
||||
{
|
||||
vc_container_helper_format_debug(ctx, indent, "%s: %"PRIi64, name, value);
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
716
gfx/include/userland/containers/core/containers_io_helpers.h
Normal file
716
gfx/include/userland/containers/core/containers_io_helpers.h
Normal file
@ -0,0 +1,716 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef VC_CONTAINERS_IO_HELPERS_H
|
||||
#define VC_CONTAINERS_IO_HELPERS_H
|
||||
|
||||
/** \file containers_io_helpers.h
|
||||
* Helper functions and macros which provide functionality which is often used by containers
|
||||
*/
|
||||
|
||||
#include "containers/core/containers_io.h"
|
||||
#include "containers/core/containers_utils.h"
|
||||
|
||||
/*****************************************************************************
|
||||
* Helper inline functions to read integers from an i/o stream
|
||||
*****************************************************************************/
|
||||
|
||||
/** Reads an unsigned 8 bits integer from an i/o stream.
|
||||
* \param io Pointer to the VC_CONTAINER_IO_T instance to use
|
||||
* \return The integer read. In case of failure during the read,
|
||||
* this will return a value of 0.
|
||||
*/
|
||||
STATIC_INLINE uint8_t vc_container_io_read_uint8(VC_CONTAINER_IO_T *io)
|
||||
{
|
||||
uint8_t value;
|
||||
size_t ret = vc_container_io_read(io, &value, 1);
|
||||
return ret == 1 ? value : 0;
|
||||
}
|
||||
|
||||
/** Reads a FOURCC from an i/o stream.
|
||||
* \param io Pointer to the VC_CONTAINER_IO_T instance to use
|
||||
* \return The FOURCC to read. In case of failure during the read,
|
||||
* this will return a value of 0.
|
||||
*/
|
||||
STATIC_INLINE VC_CONTAINER_FOURCC_T vc_container_io_read_fourcc(VC_CONTAINER_IO_T *io)
|
||||
{
|
||||
VC_CONTAINER_FOURCC_T value;
|
||||
size_t ret = vc_container_io_read(io, (int8_t *)&value, 4);
|
||||
return ret == 4 ? value : 0;
|
||||
}
|
||||
|
||||
/** Reads an unsigned 16 bits big endian integer from an i/o stream.
|
||||
* \param io Pointer to the VC_CONTAINER_IO_T instance to use
|
||||
* \return The integer read. In case of failure during the read,
|
||||
* this will return a value of 0.
|
||||
*/
|
||||
STATIC_INLINE uint16_t vc_container_io_read_be_uint16(VC_CONTAINER_IO_T *io)
|
||||
{
|
||||
uint8_t value[2];
|
||||
size_t ret = vc_container_io_read(io, value, 2);
|
||||
return ret == 2 ? (value[0] << 8) | value[1] : 0;
|
||||
}
|
||||
|
||||
/** Reads an unsigned 24 bits big endian integer from an i/o stream.
|
||||
* \param io Pointer to the VC_CONTAINER_IO_T instance to use
|
||||
* \return The integer read. In case of failure during the read,
|
||||
* this will return a value of 0.
|
||||
*/
|
||||
STATIC_INLINE uint32_t vc_container_io_read_be_uint24(VC_CONTAINER_IO_T *io)
|
||||
{
|
||||
uint8_t value[3];
|
||||
size_t ret = vc_container_io_read(io, value, 3);
|
||||
return ret == 3 ? (value[0] << 16) | (value[1] << 8) | value[2] : 0;
|
||||
}
|
||||
|
||||
/** Reads an unsigned 32 bits big endian integer from an i/o stream.
|
||||
* \param io Pointer to the VC_CONTAINER_IO_T instance to use
|
||||
* \return The integer read. In case of failure during the read,
|
||||
* this will return a value of 0.
|
||||
*/
|
||||
STATIC_INLINE uint32_t vc_container_io_read_be_uint32(VC_CONTAINER_IO_T *io)
|
||||
{
|
||||
uint8_t value[4];
|
||||
size_t ret = vc_container_io_read(io, value, 4);
|
||||
return ret == 4 ? (value[0] << 24) | (value[1] << 16) | (value[2] << 8) | value[3] : 0;
|
||||
}
|
||||
|
||||
/** Reads an unsigned 40 bits big endian integer from an i/o stream.
|
||||
* \param io Pointer to the VC_CONTAINER_IO_T instance to use
|
||||
* \return The integer read. In case of failure during the read,
|
||||
* this will return a value of 0.
|
||||
*/
|
||||
STATIC_INLINE uint64_t vc_container_io_read_be_uint40(VC_CONTAINER_IO_T *io)
|
||||
{
|
||||
uint8_t value[5];
|
||||
uint32_t value1, value2;
|
||||
size_t ret = vc_container_io_read(io, value, 5);
|
||||
|
||||
value1 = (value[0] << 24) | (value[1] << 16) | (value[2] << 8) | value[3];
|
||||
value2 = value[4];
|
||||
|
||||
return ret == 5 ? (((uint64_t)value1) << 8)|value2 : 0;
|
||||
}
|
||||
|
||||
/** Reads an unsigned 48 bits big endian integer from an i/o stream.
|
||||
* \param io Pointer to the VC_CONTAINER_IO_T instance to use
|
||||
* \return The integer read. In case of failure during the read,
|
||||
* this will return a value of 0.
|
||||
*/
|
||||
STATIC_INLINE uint64_t vc_container_io_read_be_uint48(VC_CONTAINER_IO_T *io)
|
||||
{
|
||||
uint8_t value[6];
|
||||
uint32_t value1, value2;
|
||||
size_t ret = vc_container_io_read(io, value, 6);
|
||||
|
||||
value1 = (value[0] << 24) | (value[1] << 16) | (value[2] << 8) | value[3];
|
||||
value2 = (value[4] << 8) | value[5];
|
||||
|
||||
return ret == 6 ? (((uint64_t)value1) << 16)|value2 : 0;
|
||||
}
|
||||
|
||||
/** Reads an unsigned 56 bits big endian integer from an i/o stream.
|
||||
* \param io Pointer to the VC_CONTAINER_IO_T instance to use
|
||||
* \return The integer read. In case of failure during the read,
|
||||
* this will return a value of 0.
|
||||
*/
|
||||
STATIC_INLINE uint64_t vc_container_io_read_be_uint56(VC_CONTAINER_IO_T *io)
|
||||
{
|
||||
uint8_t value[7];
|
||||
uint32_t value1, value2;
|
||||
size_t ret = vc_container_io_read(io, value, 7);
|
||||
|
||||
value1 = (value[0] << 24) | (value[1] << 16) | (value[2] << 8) | value[3];
|
||||
value2 = (value[4] << 16) | (value[5] << 8) | value[6];
|
||||
|
||||
return ret == 7 ? (((uint64_t)value1) << 24)|value2 : 0;
|
||||
}
|
||||
|
||||
/** Reads an unsigned 64 bits big endian integer from an i/o stream.
|
||||
* \param io Pointer to the VC_CONTAINER_IO_T instance to use
|
||||
* \return The integer read. In case of failure during the read,
|
||||
* this will return a value of 0.
|
||||
*/
|
||||
STATIC_INLINE uint64_t vc_container_io_read_be_uint64(VC_CONTAINER_IO_T *io)
|
||||
{
|
||||
uint8_t value[8];
|
||||
uint32_t value1, value2;
|
||||
size_t ret = vc_container_io_read(io, value, 8);
|
||||
|
||||
value1 = (value[0] << 24) | (value[1] << 16) | (value[2] << 8) | value[3];
|
||||
value2 = (value[4] << 24) | (value[5] << 16) | (value[6] << 8) | value[7];
|
||||
|
||||
return ret == 8 ? (((uint64_t)value1) << 32)|value2 : 0;
|
||||
}
|
||||
|
||||
/** Reads an unsigned 16 bits little endian integer from an i/o stream.
|
||||
* \param io Pointer to the VC_CONTAINER_IO_T instance to use
|
||||
* \return The integer read. In case of failure during the read,
|
||||
* this will return a value of 0.
|
||||
*/
|
||||
STATIC_INLINE uint16_t vc_container_io_read_le_uint16(VC_CONTAINER_IO_T *io)
|
||||
{
|
||||
uint8_t value[2];
|
||||
size_t ret = vc_container_io_read(io, value, 2);
|
||||
return ret == 2 ? (value[1] << 8) | value[0] : 0;
|
||||
}
|
||||
|
||||
/** Reads an unsigned 24 bits little endian integer from an i/o stream.
|
||||
* \param io Pointer to the VC_CONTAINER_IO_T instance to use
|
||||
* \return The integer read. In case of failure during the read,
|
||||
* this will return a value of 0.
|
||||
*/
|
||||
STATIC_INLINE uint32_t vc_container_io_read_le_uint24(VC_CONTAINER_IO_T *io)
|
||||
{
|
||||
uint8_t value[3];
|
||||
size_t ret = vc_container_io_read(io, value, 3);
|
||||
return ret == 3 ? (value[2] << 16) | (value[1] << 8) | value[0] : 0;
|
||||
}
|
||||
|
||||
/** Reads an unsigned 32 bits little endian integer from an i/o stream.
|
||||
* \param io Pointer to the VC_CONTAINER_IO_T instance to use
|
||||
* \return The integer read. In case of failure during the read,
|
||||
* this will return a value of 0.
|
||||
*/
|
||||
STATIC_INLINE uint32_t vc_container_io_read_le_uint32(VC_CONTAINER_IO_T *io)
|
||||
{
|
||||
uint8_t value[4];
|
||||
size_t ret = vc_container_io_read(io, value, 4);
|
||||
return ret == 4 ? (value[3] << 24) | (value[2] << 16) | (value[1] << 8) | value[0] : 0;
|
||||
}
|
||||
|
||||
/** Reads an unsigned 40 bits little endian integer from an i/o stream.
|
||||
* \param io Pointer to the VC_CONTAINER_IO_T instance to use
|
||||
* \return The integer read. In case of failure during the read,
|
||||
* this will return a value of 0.
|
||||
*/
|
||||
STATIC_INLINE uint64_t vc_container_io_read_le_uint40(VC_CONTAINER_IO_T *io)
|
||||
{
|
||||
uint8_t value[5];
|
||||
uint32_t value1, value2;
|
||||
size_t ret = vc_container_io_read(io, value, 5);
|
||||
|
||||
value1 = (value[3] << 24) | (value[2] << 16) | (value[1] << 8) | value[0];
|
||||
value2 = value[4];
|
||||
|
||||
return ret == 5 ? (((uint64_t)value2) << 32)|value1 : 0;
|
||||
}
|
||||
|
||||
/** Reads an unsigned 48 bits little endian integer from an i/o stream.
|
||||
* \param io Pointer to the VC_CONTAINER_IO_T instance to use
|
||||
* \return The integer read. In case of failure during the read,
|
||||
* this will return a value of 0.
|
||||
*/
|
||||
STATIC_INLINE uint64_t vc_container_io_read_le_uint48(VC_CONTAINER_IO_T *io)
|
||||
{
|
||||
uint8_t value[6];
|
||||
uint32_t value1, value2;
|
||||
size_t ret = vc_container_io_read(io, value, 6);
|
||||
|
||||
value1 = (value[3] << 24) | (value[2] << 16) | (value[1] << 8) | value[0];
|
||||
value2 = (value[5] << 8) | value[4];
|
||||
|
||||
return ret == 6 ? (((uint64_t)value2) << 32)|value1 : 0;
|
||||
}
|
||||
|
||||
/** Reads an unsigned 56 bits little endian integer from an i/o stream.
|
||||
* \param io Pointer to the VC_CONTAINER_IO_T instance to use
|
||||
* \return The integer read. In case of failure during the read,
|
||||
* this will return a value of 0.
|
||||
*/
|
||||
STATIC_INLINE uint64_t vc_container_io_read_le_uint56(VC_CONTAINER_IO_T *io)
|
||||
{
|
||||
uint8_t value[7];
|
||||
uint32_t value1, value2;
|
||||
size_t ret = vc_container_io_read(io, value, 7);
|
||||
|
||||
value1 = (value[3] << 24) | (value[2] << 16) | (value[1] << 8) | value[0];
|
||||
value2 = (value[6] << 16) | (value[5] << 8) | value[4];
|
||||
|
||||
return ret == 7 ? (((uint64_t)value2) << 32)|value1 : 0;
|
||||
}
|
||||
|
||||
/** Reads an unsigned 64 bits little endian integer from an i/o stream.
|
||||
* \param io Pointer to the VC_CONTAINER_IO_T instance to use
|
||||
* \return The integer read. In case of failure during the read,
|
||||
* this will return a value of 0.
|
||||
*/
|
||||
STATIC_INLINE uint64_t vc_container_io_read_le_uint64(VC_CONTAINER_IO_T *io)
|
||||
{
|
||||
uint8_t value[8];
|
||||
uint32_t value1, value2;
|
||||
size_t ret = vc_container_io_read(io, value, 8);
|
||||
|
||||
value1 = (value[3] << 24) | (value[2] << 16) | (value[1] << 8) | value[0];
|
||||
value2 = (value[7] << 24) | (value[6] << 16) | (value[5] << 8) | value[4];
|
||||
|
||||
return ret == 8 ? (((uint64_t)value2) << 32)|value1 : 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Helper inline functions to peek integers from an i/o stream
|
||||
*****************************************************************************/
|
||||
|
||||
/** Peeks an unsigned 8 bits integer from an i/o stream.
|
||||
* \param io Pointer to the VC_CONTAINER_IO_T instance to use
|
||||
* \return The integer read. In case of failure during the read,
|
||||
* this will return a value of 0.
|
||||
*/
|
||||
STATIC_INLINE uint8_t vc_container_io_peek_uint8(VC_CONTAINER_IO_T *io)
|
||||
{
|
||||
uint8_t value;
|
||||
size_t ret = vc_container_io_peek(io, &value, 1);
|
||||
return ret == 1 ? value : 0;
|
||||
}
|
||||
|
||||
/** Peeks an unsigned 16 bits big endian integer from an i/o stream.
|
||||
* \param io Pointer to the VC_CONTAINER_IO_T instance to use
|
||||
* \return The integer read. In case of failure during the read,
|
||||
* this will return a value of 0.
|
||||
*/
|
||||
STATIC_INLINE uint16_t vc_container_io_peek_be_uint16(VC_CONTAINER_IO_T *io)
|
||||
{
|
||||
uint8_t value[2];
|
||||
size_t ret = vc_container_io_peek(io, value, 2);
|
||||
return ret == 2 ? (value[0] << 8) | value[1] : 0;
|
||||
}
|
||||
|
||||
/** Peeks an unsigned 24 bits big endian integer from an i/o stream.
|
||||
* \param io Pointer to the VC_CONTAINER_IO_T instance to use
|
||||
* \return The integer read. In case of failure during the read,
|
||||
* this will return a value of 0.
|
||||
*/
|
||||
STATIC_INLINE uint32_t vc_container_io_peek_be_uint24(VC_CONTAINER_IO_T *io)
|
||||
{
|
||||
uint8_t value[3];
|
||||
size_t ret = vc_container_io_peek(io, value, 3);
|
||||
return ret == 3 ? (value[0] << 16) | (value[1] << 8) | value[2] : 0;
|
||||
}
|
||||
|
||||
/** Peeks an unsigned 32 bits big endian integer from an i/o stream.
|
||||
* \param io Pointer to the VC_CONTAINER_IO_T instance to use
|
||||
* \return The integer read. In case of failure during the read,
|
||||
* this will return a value of 0.
|
||||
*/
|
||||
STATIC_INLINE uint32_t vc_container_io_peek_be_uint32(VC_CONTAINER_IO_T *io)
|
||||
{
|
||||
uint8_t value[4];
|
||||
size_t ret = vc_container_io_peek(io, value, 4);
|
||||
return ret == 4 ? (value[0] << 24) | (value[1] << 16) | (value[2] << 8) | value[3] : 0;
|
||||
}
|
||||
|
||||
/** Peeks an unsigned 64 bits big endian integer from an i/o stream.
|
||||
* \param io Pointer to the VC_CONTAINER_IO_T instance to use
|
||||
* \return The integer read. In case of failure during the read,
|
||||
* this will return a value of 0.
|
||||
*/
|
||||
STATIC_INLINE uint64_t vc_container_io_peek_be_uint64(VC_CONTAINER_IO_T *io)
|
||||
{
|
||||
uint8_t value[8];
|
||||
uint32_t value1, value2;
|
||||
size_t ret = vc_container_io_peek(io, value, 8);
|
||||
|
||||
value1 = (value[0] << 24) | (value[1] << 16) | (value[2] << 8) | value[3];
|
||||
value2 = (value[4] << 24) | (value[5] << 16) | (value[6] << 8) | value[7];
|
||||
|
||||
return ret == 8 ? (((uint64_t)value1) << 32)|value2 : 0;
|
||||
}
|
||||
|
||||
/** Peeks an unsigned 16 bits little endian integer from an i/o stream.
|
||||
* \param io Pointer to the VC_CONTAINER_IO_T instance to use
|
||||
* \return The integer read. In case of failure during the read,
|
||||
* this will return a value of 0.
|
||||
*/
|
||||
STATIC_INLINE uint16_t vc_container_io_peek_le_uint16(VC_CONTAINER_IO_T *io)
|
||||
{
|
||||
uint8_t value[2];
|
||||
size_t ret = vc_container_io_peek(io, value, 2);
|
||||
return ret == 2 ? (value[1] << 8) | value[0] : 0;
|
||||
}
|
||||
|
||||
/** Peeks an unsigned 24 bits little endian integer from an i/o stream.
|
||||
* \param io Pointer to the VC_CONTAINER_IO_T instance to use
|
||||
* \return The integer read. In case of failure during the read,
|
||||
* this will return a value of 0.
|
||||
*/
|
||||
STATIC_INLINE uint32_t vc_container_io_peek_le_uint24(VC_CONTAINER_IO_T *io)
|
||||
{
|
||||
uint8_t value[3];
|
||||
size_t ret = vc_container_io_peek(io, value, 3);
|
||||
return ret == 3 ? (value[2] << 16) | (value[1] << 8) | value[0] : 0;
|
||||
}
|
||||
|
||||
/** Peeks an unsigned 32 bits little endian integer from an i/o stream.
|
||||
* \param io Pointer to the VC_CONTAINER_IO_T instance to use
|
||||
* \return The integer read. In case of failure during the read,
|
||||
* this will return a value of 0.
|
||||
*/
|
||||
STATIC_INLINE uint32_t vc_container_io_peek_le_uint32(VC_CONTAINER_IO_T *io)
|
||||
{
|
||||
uint8_t value[4];
|
||||
size_t ret = vc_container_io_peek(io, value, 4);
|
||||
return ret == 4 ? (value[3] << 24) | (value[2] << 16) | (value[1] << 8) | value[0] : 0;
|
||||
}
|
||||
|
||||
/** Peeks an unsigned 64 bits little endian integer from an i/o stream.
|
||||
* \param io Pointer to the VC_CONTAINER_IO_T instance to use
|
||||
* \return The integer read. In case of failure during the read,
|
||||
* this will return a value of 0.
|
||||
*/
|
||||
STATIC_INLINE uint64_t vc_container_io_peek_le_uint64(VC_CONTAINER_IO_T *io)
|
||||
{
|
||||
uint8_t value[8];
|
||||
uint32_t value1, value2;
|
||||
size_t ret = vc_container_io_peek(io, value, 8);
|
||||
|
||||
value1 = (value[3] << 24) | (value[2] << 16) | (value[1] << 8) | value[0];
|
||||
value2 = (value[7] << 24) | (value[6] << 16) | (value[5] << 8) | value[4];
|
||||
|
||||
return ret == 8 ? (((uint64_t)value2) << 32)|value1 : 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Helper inline functions to write integers to an i/o stream
|
||||
*****************************************************************************/
|
||||
|
||||
/** Writes an unsigned 8 bits integer to an i/o stream.
|
||||
* \param io Pointer to the VC_CONTAINER_IO_T instance to use
|
||||
* \param value The integer to write.
|
||||
* \return The status of the operation.
|
||||
*/
|
||||
STATIC_INLINE VC_CONTAINER_STATUS_T vc_container_io_write_uint8(VC_CONTAINER_IO_T *io, uint8_t value)
|
||||
{
|
||||
size_t ret = vc_container_io_write(io, &value, 1);
|
||||
return ret == 1 ? VC_CONTAINER_SUCCESS : VC_CONTAINER_ERROR_FAILED;
|
||||
}
|
||||
|
||||
/** Writes a FOURCC to an i/o stream.
|
||||
* \param io Pointer to the VC_CONTAINER_IO_T instance to use
|
||||
* \param value The FOURCC to write.
|
||||
* \return The status of the operation.
|
||||
*/
|
||||
STATIC_INLINE VC_CONTAINER_STATUS_T vc_container_io_write_fourcc(VC_CONTAINER_IO_T *io, VC_CONTAINER_FOURCC_T value)
|
||||
{
|
||||
size_t ret = vc_container_io_write(io, (uint8_t *)&value, 4);
|
||||
return ret == 4 ? VC_CONTAINER_SUCCESS : VC_CONTAINER_ERROR_FAILED;
|
||||
}
|
||||
|
||||
/** Writes an unsigned 16 bits big endian integer to an i/o stream.
|
||||
* \param io Pointer to the VC_CONTAINER_IO_T instance to use
|
||||
* \param value The integer to write.
|
||||
* \return The status of the operation.
|
||||
*/
|
||||
STATIC_INLINE VC_CONTAINER_STATUS_T vc_container_io_write_be_uint16(VC_CONTAINER_IO_T *io, uint16_t value)
|
||||
{
|
||||
uint8_t bytes[2] = {(uint8_t)(value >> 8), (uint8_t)value};
|
||||
size_t ret = vc_container_io_write(io, bytes, 2);
|
||||
return ret == 2 ? VC_CONTAINER_SUCCESS : VC_CONTAINER_ERROR_FAILED;
|
||||
}
|
||||
|
||||
/** Writes an unsigned 24 bits big endian integer to an i/o stream.
|
||||
* \param io Pointer to the VC_CONTAINER_IO_T instance to use
|
||||
* \param value The integer to write.
|
||||
* \return The status of the operation.
|
||||
*/
|
||||
STATIC_INLINE VC_CONTAINER_STATUS_T vc_container_io_write_be_uint24(VC_CONTAINER_IO_T *io, uint32_t value)
|
||||
{
|
||||
uint8_t bytes[3] = {(uint8_t)(value >> 16), (uint8_t)(value >> 8), (uint8_t)value};
|
||||
size_t ret = vc_container_io_write(io, bytes, 3);
|
||||
return ret == 3 ? VC_CONTAINER_SUCCESS : VC_CONTAINER_ERROR_FAILED;
|
||||
}
|
||||
|
||||
/** Writes an unsigned 32 bits big endian integer to an i/o stream.
|
||||
* \param io Pointer to the VC_CONTAINER_IO_T instance to use
|
||||
* \param value The integer to write.
|
||||
* \return The status of the operation.
|
||||
*/
|
||||
STATIC_INLINE VC_CONTAINER_STATUS_T vc_container_io_write_be_uint32(VC_CONTAINER_IO_T *io, uint32_t value)
|
||||
{
|
||||
uint8_t bytes[4] = {value >> 24, value >> 16, value >> 8, value};
|
||||
size_t ret = vc_container_io_write(io, bytes, 4);
|
||||
return ret == 4 ? VC_CONTAINER_SUCCESS : VC_CONTAINER_ERROR_FAILED;
|
||||
}
|
||||
|
||||
/** Writes an unsigned 64 bits big endian integer to an i/o stream.
|
||||
* \param io Pointer to the VC_CONTAINER_IO_T instance to use
|
||||
* \param value The integer to write.
|
||||
* \return The status of the operation.
|
||||
*/
|
||||
STATIC_INLINE VC_CONTAINER_STATUS_T vc_container_io_write_be_uint64(VC_CONTAINER_IO_T *io, uint64_t value)
|
||||
{
|
||||
uint8_t bytes[8] =
|
||||
{
|
||||
(uint8_t)(value >> 56),
|
||||
(uint8_t)(value >> 48),
|
||||
(uint8_t)(value >> 40),
|
||||
(uint8_t)(value >> 32),
|
||||
(uint8_t)(value >> 24),
|
||||
(uint8_t)(value >> 16),
|
||||
(uint8_t)(value >> 8),
|
||||
(uint8_t) value
|
||||
};
|
||||
size_t ret = vc_container_io_write(io, bytes, 8);
|
||||
return ret == 8 ? VC_CONTAINER_SUCCESS : VC_CONTAINER_ERROR_FAILED;
|
||||
}
|
||||
|
||||
/** Writes an unsigned 16 bits little endian integer to an i/o stream.
|
||||
* \param io Pointer to the VC_CONTAINER_IO_T instance to use
|
||||
* \param value The integer to write.
|
||||
* \return The status of the operation.
|
||||
*/
|
||||
STATIC_INLINE VC_CONTAINER_STATUS_T vc_container_io_write_le_uint16(VC_CONTAINER_IO_T *io, uint16_t value)
|
||||
{
|
||||
uint8_t bytes[2] = {(uint8_t)value, (uint8_t)(value >> 8)};
|
||||
size_t ret = vc_container_io_write(io, bytes, 2);
|
||||
return ret == 2 ? VC_CONTAINER_SUCCESS : VC_CONTAINER_ERROR_FAILED;
|
||||
}
|
||||
|
||||
/** Writes an unsigned 24 bits little endian integer to an i/o stream.
|
||||
* \param io Pointer to the VC_CONTAINER_IO_T instance to use
|
||||
* \param value The integer to write.
|
||||
* \return The status of the operation.
|
||||
*/
|
||||
STATIC_INLINE VC_CONTAINER_STATUS_T vc_container_io_write_le_uint24(VC_CONTAINER_IO_T *io, uint32_t value)
|
||||
{
|
||||
uint8_t bytes[3] = {value, value >> 8, value >> 16};
|
||||
size_t ret = vc_container_io_write(io, bytes, 3);
|
||||
return ret == 3 ? VC_CONTAINER_SUCCESS : VC_CONTAINER_ERROR_FAILED;
|
||||
}
|
||||
|
||||
/** Writes an unsigned 32 bits little endian integer to an i/o stream.
|
||||
* \param io Pointer to the VC_CONTAINER_IO_T instance to use
|
||||
* \param value The integer to write.
|
||||
* \return The status of the operation.
|
||||
*/
|
||||
STATIC_INLINE VC_CONTAINER_STATUS_T vc_container_io_write_le_uint32(VC_CONTAINER_IO_T *io, uint32_t value)
|
||||
{
|
||||
uint8_t bytes[4] = {value, value >> 8, value >> 16, value >> 24};
|
||||
size_t ret = vc_container_io_write(io, bytes, 4);
|
||||
return ret == 4 ? VC_CONTAINER_SUCCESS : VC_CONTAINER_ERROR_FAILED;
|
||||
}
|
||||
|
||||
/** Writes an unsigned 64 bits little endian integer to an i/o stream.
|
||||
* \param io Pointer to the VC_CONTAINER_IO_T instance to use
|
||||
* \param value The integer to write.
|
||||
* \return The status of the operation.
|
||||
*/
|
||||
STATIC_INLINE VC_CONTAINER_STATUS_T vc_container_io_write_le_uint64(VC_CONTAINER_IO_T *io, uint64_t value)
|
||||
{
|
||||
uint8_t bytes[8] =
|
||||
{
|
||||
(uint8_t) value,
|
||||
(uint8_t)(value >> 8),
|
||||
(uint8_t)(value >> 16),
|
||||
(uint8_t)(value >> 24),
|
||||
(uint8_t)(value >> 32),
|
||||
(uint8_t)(value >> 40),
|
||||
(uint8_t)(value >> 48),
|
||||
(uint8_t)(value >> 56)
|
||||
};
|
||||
size_t ret = vc_container_io_write(io, bytes, 8);
|
||||
return ret == 8 ? VC_CONTAINER_SUCCESS : VC_CONTAINER_ERROR_FAILED;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Helper macros for accessing the i/o stream. These will also call the right
|
||||
* functions depending on the endianness defined.
|
||||
*****************************************************************************/
|
||||
|
||||
/** Macro which returns the current position within the stream */
|
||||
#define STREAM_POSITION(ctx) (ctx)->priv->io->offset
|
||||
/** Macro which returns true if the end of stream has been reached */
|
||||
#define STREAM_EOS(ctx) ((ctx)->priv->io->status == VC_CONTAINER_ERROR_EOS)
|
||||
/** Macro which returns the status of the stream */
|
||||
#define STREAM_STATUS(ctx) (ctx)->priv->io->status
|
||||
/** Macro which returns true if an error other than end of stream has occurred */
|
||||
#define STREAM_ERROR(ctx) ((ctx)->priv->io->status && (ctx)->priv->io->status != VC_CONTAINER_ERROR_EOS)
|
||||
/** Macro which returns true if we can seek into the stream */
|
||||
#define STREAM_SEEKABLE(ctx) (!((ctx)->priv->io->capabilities & VC_CONTAINER_IO_CAPS_CANT_SEEK))
|
||||
|
||||
#define PEEK_BYTES(ctx, buffer, size) vc_container_io_peek((ctx)->priv->io, buffer, (size_t)(size))
|
||||
#define READ_BYTES(ctx, buffer, size) vc_container_io_read((ctx)->priv->io, buffer, (size_t)(size))
|
||||
#define SKIP_BYTES(ctx, size) vc_container_io_skip((ctx)->priv->io, (size_t)(size))
|
||||
#define SEEK(ctx, off) vc_container_io_seek((ctx)->priv->io, (int64_t)(off))
|
||||
#define CACHE_BYTES(ctx, size) vc_container_io_cache((ctx)->priv->io, (size_t)(size))
|
||||
|
||||
#define _SKIP_GUID(ctx) vc_container_io_skip((ctx)->priv->io, 16)
|
||||
#define _SKIP_U8(ctx) (vc_container_io_skip((ctx)->priv->io, 1) != 1)
|
||||
#define _SKIP_U16(ctx) (vc_container_io_skip((ctx)->priv->io, 2) != 2)
|
||||
#define _SKIP_U24(ctx) (vc_container_io_skip((ctx)->priv->io, 3) != 3)
|
||||
#define _SKIP_U32(ctx) (vc_container_io_skip((ctx)->priv->io, 4) != 4)
|
||||
#define _SKIP_U64(ctx) (vc_container_io_skip((ctx)->priv->io, 8) != 8)
|
||||
#define _SKIP_FOURCC(ctx) (vc_container_io_skip((ctx)->priv->io, 4) != 4)
|
||||
|
||||
#define _READ_GUID(ctx, buffer) vc_container_io_read((ctx)->priv->io, buffer, 16)
|
||||
#define _READ_U8(ctx) vc_container_io_read_uint8((ctx)->priv->io)
|
||||
#define _READ_FOURCC(ctx) vc_container_io_read_fourcc((ctx)->priv->io)
|
||||
#define PEEK_GUID(ctx, buffer) vc_container_io_peek((ctx)->priv->io, buffer, 16)
|
||||
#define PEEK_U8(ctx) vc_container_io_peek_uint8((ctx)->priv->io)
|
||||
#ifdef CONTAINER_IS_BIG_ENDIAN
|
||||
# define _READ_U16(ctx) vc_container_io_read_be_uint16((ctx)->priv->io)
|
||||
# define _READ_U24(ctx) vc_container_io_read_be_uint24((ctx)->priv->io)
|
||||
# define _READ_U32(ctx) vc_container_io_read_be_uint32((ctx)->priv->io)
|
||||
# define _READ_U40(ctx) vc_container_io_read_be_uint40((ctx)->priv->io)
|
||||
# define _READ_U48(ctx) vc_container_io_read_be_uint48((ctx)->priv->io)
|
||||
# define _READ_U56(ctx) vc_container_io_read_be_uint56((ctx)->priv->io)
|
||||
# define _READ_U64(ctx) vc_container_io_read_be_uint64((ctx)->priv->io)
|
||||
# define PEEK_U16(ctx) vc_container_io_peek_be_uint16((ctx)->priv->io)
|
||||
# define PEEK_U24(ctx) vc_container_io_peek_be_uint24((ctx)->priv->io)
|
||||
# define PEEK_U32(ctx) vc_container_io_peek_be_uint32((ctx)->priv->io)
|
||||
# define PEEK_U64(ctx) vc_container_io_peek_be_uint64((ctx)->priv->io)
|
||||
#else
|
||||
# define _READ_U16(ctx) vc_container_io_read_le_uint16((ctx)->priv->io)
|
||||
# define _READ_U24(ctx) vc_container_io_read_le_uint24((ctx)->priv->io)
|
||||
# define _READ_U32(ctx) vc_container_io_read_le_uint32((ctx)->priv->io)
|
||||
# define _READ_U40(ctx) vc_container_io_read_le_uint40((ctx)->priv->io)
|
||||
# define _READ_U48(ctx) vc_container_io_read_le_uint48((ctx)->priv->io)
|
||||
# define _READ_U56(ctx) vc_container_io_read_le_uint56((ctx)->priv->io)
|
||||
# define _READ_U64(ctx) vc_container_io_read_le_uint64((ctx)->priv->io)
|
||||
# define PEEK_U16(ctx) vc_container_io_peek_le_uint16((ctx)->priv->io)
|
||||
# define PEEK_U24(ctx) vc_container_io_peek_le_uint24((ctx)->priv->io)
|
||||
# define PEEK_U32(ctx) vc_container_io_peek_le_uint32((ctx)->priv->io)
|
||||
# define PEEK_U64(ctx) vc_container_io_peek_le_uint64((ctx)->priv->io)
|
||||
#endif
|
||||
|
||||
#define WRITE_BYTES(ctx, buffer, size) vc_container_io_write((ctx)->priv->io, buffer, (size_t)(size))
|
||||
#define _WRITE_GUID(ctx, buffer) vc_container_io_write((ctx)->priv->io, buffer, 16)
|
||||
#define _WRITE_U8(ctx, v) vc_container_io_write_uint8((ctx)->priv->io, v)
|
||||
#define _WRITE_FOURCC(ctx, v) vc_container_io_write_fourcc((ctx)->priv->io, v)
|
||||
#ifdef CONTAINER_IS_BIG_ENDIAN
|
||||
# define _WRITE_U16(ctx, v) vc_container_io_write_be_uint16((ctx)->priv->io, v)
|
||||
# define _WRITE_U24(ctx, v) vc_container_io_write_be_uint24((ctx)->priv->io, v)
|
||||
# define _WRITE_U32(ctx, v) vc_container_io_write_be_uint32((ctx)->priv->io, v)
|
||||
# define _WRITE_U64(ctx, v) vc_container_io_write_be_uint64((ctx)->priv->io, v)
|
||||
#else
|
||||
# define _WRITE_U16(ctx, v) vc_container_io_write_le_uint16((ctx)->priv->io, v)
|
||||
# define _WRITE_U24(ctx, v) vc_container_io_write_le_uint24((ctx)->priv->io, v)
|
||||
# define _WRITE_U32(ctx, v) vc_container_io_write_le_uint32((ctx)->priv->io, v)
|
||||
# define _WRITE_U64(ctx, v) vc_container_io_write_le_uint64((ctx)->priv->io, v)
|
||||
#endif
|
||||
|
||||
#ifndef CONTAINER_HELPER_LOG_INDENT
|
||||
# define CONTAINER_HELPER_LOG_INDENT(a) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONTAINER_IS_BIG_ENDIAN
|
||||
# define LOG_FORMAT_TYPE_UINT LOG_FORMAT_TYPE_UINT_BE
|
||||
# define LOG_FORMAT_TYPE_STRING_UTF16 LOG_FORMAT_TYPE_STRING_UTF16_BE
|
||||
#else
|
||||
# define LOG_FORMAT_TYPE_UINT LOG_FORMAT_TYPE_UINT_LE
|
||||
# define LOG_FORMAT_TYPE_STRING_UTF16 LOG_FORMAT_TYPE_STRING_UTF16_LE
|
||||
#endif
|
||||
|
||||
#ifndef ENABLE_CONTAINERS_LOG_FORMAT
|
||||
#define SKIP_GUID(ctx,n) _SKIP_GUID(ctx)
|
||||
#define SKIP_U8(ctx,n) _SKIP_U8(ctx)
|
||||
#define SKIP_U16(ctx,n) _SKIP_U16(ctx)
|
||||
#define SKIP_U24(ctx,n) _SKIP_U24(ctx)
|
||||
#define SKIP_U32(ctx,n) _SKIP_U32(ctx)
|
||||
#define SKIP_U64(ctx,n) _SKIP_U64(ctx)
|
||||
#define SKIP_FOURCC(ctx,n) _SKIP_FOURCC(ctx)
|
||||
#define READ_GUID(ctx,buffer,n) _READ_GUID(ctx,(uint8_t *)buffer)
|
||||
#define READ_U8(ctx,n) _READ_U8(ctx)
|
||||
#define READ_U16(ctx,n) _READ_U16(ctx)
|
||||
#define READ_U24(ctx,n) _READ_U24(ctx)
|
||||
#define READ_U32(ctx,n) _READ_U32(ctx)
|
||||
#define READ_U40(ctx,n) _READ_U40(ctx)
|
||||
#define READ_U48(ctx,n) _READ_U48(ctx)
|
||||
#define READ_U56(ctx,n) _READ_U56(ctx)
|
||||
#define READ_U64(ctx,n) _READ_U64(ctx)
|
||||
#define READ_FOURCC(ctx,n) _READ_FOURCC(ctx)
|
||||
#define READ_STRING(ctx,buffer,sz,n) READ_BYTES(ctx,buffer,sz)
|
||||
#define READ_STRING_UTF16(ctx,buffer,sz,n) READ_BYTES(ctx,buffer,sz)
|
||||
#define SKIP_STRING(ctx,sz,n) SKIP_BYTES(ctx,sz)
|
||||
#define SKIP_STRING_UTF16(ctx,sz,n) SKIP_BYTES(ctx,sz)
|
||||
#else
|
||||
#define SKIP_GUID(ctx,n) vc_container_helper_read_debug(ctx, LOG_FORMAT_TYPE_GUID, 16, n, 0, CONTAINER_HELPER_LOG_INDENT(ctx), 1)
|
||||
#define SKIP_U8(ctx,n) vc_container_helper_read_debug(ctx, LOG_FORMAT_TYPE_UINT, 1, n, 0, CONTAINER_HELPER_LOG_INDENT(ctx), 1)
|
||||
#define SKIP_U16(ctx,n) vc_container_helper_read_debug(ctx, LOG_FORMAT_TYPE_UINT, 2, n, 0, CONTAINER_HELPER_LOG_INDENT(ctx), 1)
|
||||
#define SKIP_U24(ctx,n) vc_container_helper_read_debug(ctx, LOG_FORMAT_TYPE_UINT, 3, n, 0, CONTAINER_HELPER_LOG_INDENT(ctx), 1)
|
||||
#define SKIP_U32(ctx,n) vc_container_helper_read_debug(ctx, LOG_FORMAT_TYPE_UINT, 4, n, 0, CONTAINER_HELPER_LOG_INDENT(ctx), 1)
|
||||
#define SKIP_U64(ctx,n) vc_container_helper_read_debug(ctx, LOG_FORMAT_TYPE_UINT, 8, n, 0, CONTAINER_HELPER_LOG_INDENT(ctx), 1)
|
||||
#define SKIP_FOURCC(ctx,n) vc_container_helper_read_debug(ctx, LOG_FORMAT_TYPE_FOURCC, 4, n, 0, CONTAINER_HELPER_LOG_INDENT(ctx), 1)
|
||||
#define READ_GUID(ctx,buffer,n) vc_container_helper_read_debug(ctx, LOG_FORMAT_TYPE_GUID, 16, n, (uint8_t *)buffer, CONTAINER_HELPER_LOG_INDENT(ctx), 0)
|
||||
#define READ_U8(ctx,n) (uint8_t)vc_container_helper_read_debug(ctx, LOG_FORMAT_TYPE_UINT, 1, n, 0, CONTAINER_HELPER_LOG_INDENT(ctx), 0)
|
||||
#define READ_U16(ctx,n) (uint16_t)vc_container_helper_read_debug(ctx, LOG_FORMAT_TYPE_UINT, 2, n, 0, CONTAINER_HELPER_LOG_INDENT(ctx), 0)
|
||||
#define READ_U24(ctx,n) (uint32_t)vc_container_helper_read_debug(ctx, LOG_FORMAT_TYPE_UINT, 3, n, 0, CONTAINER_HELPER_LOG_INDENT(ctx), 0)
|
||||
#define READ_U32(ctx,n) (uint32_t)vc_container_helper_read_debug(ctx, LOG_FORMAT_TYPE_UINT, 4, n, 0, CONTAINER_HELPER_LOG_INDENT(ctx), 0)
|
||||
#define READ_U40(ctx,n) vc_container_helper_read_debug(ctx, LOG_FORMAT_TYPE_UINT, 5, n, 0, CONTAINER_HELPER_LOG_INDENT(ctx), 0)
|
||||
#define READ_U48(ctx,n) vc_container_helper_read_debug(ctx, LOG_FORMAT_TYPE_UINT, 6, n, 0, CONTAINER_HELPER_LOG_INDENT(ctx), 0)
|
||||
#define READ_U56(ctx,n) vc_container_helper_read_debug(ctx, LOG_FORMAT_TYPE_UINT, 7, n, 0, CONTAINER_HELPER_LOG_INDENT(ctx), 0)
|
||||
#define READ_U64(ctx,n) vc_container_helper_read_debug(ctx, LOG_FORMAT_TYPE_UINT, 8, n, 0, CONTAINER_HELPER_LOG_INDENT(ctx), 0)
|
||||
#define READ_FOURCC(ctx,n) vc_container_helper_read_debug(ctx, LOG_FORMAT_TYPE_FOURCC, 4, n, 0, CONTAINER_HELPER_LOG_INDENT(ctx), 0)
|
||||
#define READ_STRING_UTF16(ctx,buffer,sz,n) vc_container_helper_read_debug(ctx, LOG_FORMAT_TYPE_STRING_UTF16, sz, n, (uint8_t *)buffer, CONTAINER_HELPER_LOG_INDENT(ctx), 0)
|
||||
#define READ_STRING(ctx,buffer,sz,n) vc_container_helper_read_debug(ctx, LOG_FORMAT_TYPE_STRING, sz, n, (uint8_t *)buffer, CONTAINER_HELPER_LOG_INDENT(ctx), 0)
|
||||
#define SKIP_STRING_UTF16(ctx,sz,n) vc_container_helper_read_debug(ctx, LOG_FORMAT_TYPE_STRING_UTF16, sz, n, 0, CONTAINER_HELPER_LOG_INDENT(ctx), 1)
|
||||
#define SKIP_STRING(ctx,sz,n) vc_container_helper_read_debug(ctx, LOG_FORMAT_TYPE_STRING, sz, n, 0, CONTAINER_HELPER_LOG_INDENT(ctx), 1)
|
||||
#endif
|
||||
|
||||
#ifndef ENABLE_CONTAINERS_LOG_FORMAT
|
||||
#define WRITE_GUID(ctx,buffer,n) _WRITE_GUID(ctx,(const uint8_t *)buffer)
|
||||
#define WRITE_U8(ctx,v,n) _WRITE_U8(ctx,(uint8_t)(v))
|
||||
#define WRITE_FOURCC(ctx,v,n) _WRITE_FOURCC(ctx,(uint32_t)(v))
|
||||
#define WRITE_U16(ctx,v,n) _WRITE_U16(ctx,(uint16_t)(v))
|
||||
#define WRITE_U24(ctx,v,n) _WRITE_U24(ctx,(uint32_t)(v))
|
||||
#define WRITE_U32(ctx,v,n) _WRITE_U32(ctx,(uint32_t)(v))
|
||||
#define WRITE_U64(ctx,v,n) _WRITE_U64(ctx,(uint64_t)(v))
|
||||
#define WRITE_STRING(ctx,buffer,size,n) WRITE_BYTES(ctx, buffer, size)
|
||||
#else
|
||||
#define WRITE_GUID(ctx,buffer,n) (vc_container_helper_write_debug(ctx, LOG_FORMAT_TYPE_GUID, 16, n, UINT64_C(0), (const uint8_t *)buffer, CONTAINER_HELPER_LOG_INDENT(ctx), !(ctx)->priv->io->module) ? 0 : 16)
|
||||
#define WRITE_U8(ctx,v,n) vc_container_helper_write_debug(ctx, LOG_FORMAT_TYPE_UINT, 1, n, (uint64_t)(v), 0, CONTAINER_HELPER_LOG_INDENT(ctx), !(ctx)->priv->io->module)
|
||||
#define WRITE_FOURCC(ctx,v,n) vc_container_helper_write_debug(ctx, LOG_FORMAT_TYPE_FOURCC, 4, n, (uint64_t)(v), 0, CONTAINER_HELPER_LOG_INDENT(ctx), !(ctx)->priv->io->module)
|
||||
#define WRITE_U16(ctx,v,n) (uint16_t)vc_container_helper_write_debug(ctx, LOG_FORMAT_TYPE_UINT, 2, n, (uint64_t)(v), 0, CONTAINER_HELPER_LOG_INDENT(ctx), !(ctx)->priv->io->module)
|
||||
#define WRITE_U24(ctx,v,n) vc_container_helper_write_debug(ctx, LOG_FORMAT_TYPE_UINT, 3, n, (uint64_t)(v), 0, CONTAINER_HELPER_LOG_INDENT(ctx), !(ctx)->priv->io->module)
|
||||
#define WRITE_U32(ctx,v,n) vc_container_helper_write_debug(ctx, LOG_FORMAT_TYPE_UINT, 4, n, (uint64_t)(v), 0, CONTAINER_HELPER_LOG_INDENT(ctx), !(ctx)->priv->io->module)
|
||||
#define WRITE_U64(ctx,v,n) vc_container_helper_write_debug(ctx, LOG_FORMAT_TYPE_UINT, 8, n, (uint64_t)(v), 0, CONTAINER_HELPER_LOG_INDENT(ctx), !(ctx)->priv->io->module)
|
||||
#define WRITE_STRING(ctx,buffer,size,n) (vc_container_helper_write_debug(ctx, LOG_FORMAT_TYPE_STRING, size, n, UINT64_C(0), (const uint8_t *)buffer, CONTAINER_HELPER_LOG_INDENT(ctx), !(ctx)->priv->io->module) ? 0 : size)
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_CONTAINERS_LOG_FORMAT
|
||||
#define LOG_FORMAT(ctx, ...) do { if((ctx)->priv->io->module) vc_container_helper_format_debug(ctx, CONTAINER_HELPER_LOG_INDENT(ctx), __VA_ARGS__); } while(0)
|
||||
#else
|
||||
#define LOG_FORMAT(ctx, ...) do {} while (0)
|
||||
#endif
|
||||
|
||||
#define LOG_FORMAT_TYPE_UINT_LE 0
|
||||
#define LOG_FORMAT_TYPE_UINT_BE 1
|
||||
#define LOG_FORMAT_TYPE_STRING 2
|
||||
#define LOG_FORMAT_TYPE_STRING_UTF16_LE 3
|
||||
#define LOG_FORMAT_TYPE_STRING_UTF16_BE 4
|
||||
#define LOG_FORMAT_TYPE_FOURCC 5
|
||||
#define LOG_FORMAT_TYPE_GUID 6
|
||||
#define LOG_FORMAT_TYPE_HEX 0x100
|
||||
|
||||
uint64_t vc_container_helper_int_debug(VC_CONTAINER_T *ctx, int type, uint64_t value, const char *name, int indent);
|
||||
uint64_t vc_container_helper_read_debug(VC_CONTAINER_T *ctx, int type, int size, const char *name,
|
||||
uint8_t *buffer, int indent, int b_skip);
|
||||
VC_CONTAINER_STATUS_T vc_container_helper_write_debug(VC_CONTAINER_T *ctx, int type, int size, const char *name,
|
||||
uint64_t value, const uint8_t *buffer, int indent, int silent);
|
||||
void vc_container_helper_format_debug(VC_CONTAINER_T *ctx, int indent, const char *format, ...);
|
||||
|
||||
#endif /* VC_CONTAINERS_IO_HELPERS_H */
|
||||
/* End of file */
|
||||
/*-----------------------------------------------------------------------------*/
|
221
gfx/include/userland/containers/core/containers_list.c
Normal file
221
gfx/include/userland/containers/core/containers_list.c
Normal file
@ -0,0 +1,221 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "containers/core/containers_common.h"
|
||||
#include "containers/core/containers_list.h"
|
||||
|
||||
/******************************************************************************
|
||||
Defines and constants.
|
||||
******************************************************************************/
|
||||
|
||||
/******************************************************************************
|
||||
Type definitions
|
||||
******************************************************************************/
|
||||
|
||||
/******************************************************************************
|
||||
Function prototypes
|
||||
******************************************************************************/
|
||||
|
||||
/******************************************************************************
|
||||
Local Functions
|
||||
******************************************************************************/
|
||||
|
||||
/** Find an entry in the list, or the insertion point.
|
||||
* Uses binary sub-division to find the search item. If index is not NULL, the
|
||||
* index of the matching entry, or the point at which to insert if not found, is
|
||||
* written to that address.
|
||||
*
|
||||
* \param list The list to be searched.
|
||||
* \param entry The entry for which to search.
|
||||
* \param index Set to index of match, or insertion point if not found. May be NULL.
|
||||
* \return True if a match was found, false if not. */
|
||||
static bool vc_containers_list_find_index(const VC_CONTAINERS_LIST_T *list,
|
||||
const void *entry,
|
||||
uint32_t *index)
|
||||
{
|
||||
const char *entries = (const char *)list->entries;
|
||||
size_t entry_size = list->entry_size;
|
||||
VC_CONTAINERS_LIST_COMPARATOR_T comparator = list->comparator;
|
||||
uint32_t start = 0, end = list->size;
|
||||
uint32_t mid = end >> 1;
|
||||
bool match = false;
|
||||
|
||||
while (mid < end)
|
||||
{
|
||||
int comparison = comparator(entry, entries + mid * entry_size);
|
||||
|
||||
if (comparison < 0)
|
||||
end = mid;
|
||||
else if (comparison > 0)
|
||||
start = mid + 1;
|
||||
else {
|
||||
match = true;
|
||||
break;
|
||||
}
|
||||
|
||||
mid = (start + end) >> 1;
|
||||
}
|
||||
|
||||
if (index) *index = mid;
|
||||
return match;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
Functions exported as part of the API
|
||||
******************************************************************************/
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_CONTAINERS_LIST_T *vc_containers_list_create(uint32_t capacity,
|
||||
size_t entry_size,
|
||||
VC_CONTAINERS_LIST_COMPARATOR_T comparator)
|
||||
{
|
||||
VC_CONTAINERS_LIST_T *list;
|
||||
|
||||
list = (VC_CONTAINERS_LIST_T *)malloc(sizeof(VC_CONTAINERS_LIST_T));
|
||||
if (!list)
|
||||
return NULL;
|
||||
|
||||
/* Ensure non-zero capacity, as that signifies a read-only list */
|
||||
if (!capacity) capacity = 1;
|
||||
|
||||
list->entries = malloc(capacity * entry_size);
|
||||
if (!list->entries)
|
||||
{
|
||||
free(list);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list->size = 0;
|
||||
list->capacity = capacity;
|
||||
list->entry_size = entry_size;
|
||||
list->comparator = comparator;
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
void vc_containers_list_destroy(VC_CONTAINERS_LIST_T *list)
|
||||
{
|
||||
/* Avoid trying to destroy read-only lists */
|
||||
if (list && list->capacity)
|
||||
{
|
||||
if (list->entries)
|
||||
free(list->entries);
|
||||
free(list);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
void vc_containers_list_reset(VC_CONTAINERS_LIST_T *list)
|
||||
{
|
||||
/* Avoid trying to reset read-only lists */
|
||||
if (list && list->capacity)
|
||||
list->size = 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
bool vc_containers_list_insert(VC_CONTAINERS_LIST_T *list,
|
||||
void *new_entry,
|
||||
bool allow_duplicates)
|
||||
{
|
||||
uint32_t insert_idx;
|
||||
char *insert_ptr;
|
||||
size_t entry_size;
|
||||
bool match;
|
||||
|
||||
if (!list || !list->capacity) return false;
|
||||
|
||||
entry_size = list->entry_size;
|
||||
match = vc_containers_list_find_index(list, new_entry, &insert_idx);
|
||||
insert_ptr = (char *)list->entries + entry_size * insert_idx;
|
||||
|
||||
if (!match || allow_duplicates)
|
||||
{
|
||||
/* Ensure there is space for the new entry */
|
||||
if (list->size == list->capacity)
|
||||
{
|
||||
void *new_entries = realloc(list->entries, (list->size + 1) * entry_size);
|
||||
|
||||
if (!new_entries)
|
||||
return false;
|
||||
list->entries = new_entries;
|
||||
list->capacity++;
|
||||
}
|
||||
|
||||
/* Move up anything above the insertion point */
|
||||
if (insert_idx < list->size)
|
||||
memmove(insert_ptr + entry_size, insert_ptr, (list->size - insert_idx) * entry_size);
|
||||
|
||||
list->size++;
|
||||
}
|
||||
|
||||
/* Copy in the new entry (overwriting the old one if necessary) */
|
||||
memcpy(insert_ptr, new_entry, list->entry_size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
bool vc_containers_list_find_entry(const VC_CONTAINERS_LIST_T *list,
|
||||
void *entry)
|
||||
{
|
||||
uint32_t index;
|
||||
size_t entry_size;
|
||||
|
||||
if (!vc_containers_list_find_index(list, entry, &index))
|
||||
return false;
|
||||
|
||||
entry_size = list->entry_size;
|
||||
memcpy(entry, (const char *)list->entries + entry_size * index, entry_size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
void vc_containers_list_validate(const VC_CONTAINERS_LIST_T *list)
|
||||
{
|
||||
uint32_t ii, entry_size;
|
||||
const uint8_t *entry_ptr;
|
||||
|
||||
vc_container_assert(list);
|
||||
vc_container_assert(!list->capacity || list->size <= list->capacity);
|
||||
vc_container_assert(list->entry_size);
|
||||
vc_container_assert(list->comparator);
|
||||
vc_container_assert(list->entries);
|
||||
|
||||
/* Check all entries are in sorted order */
|
||||
entry_ptr = (const uint8_t *)list->entries;
|
||||
entry_size = list->entry_size;
|
||||
for (ii = 1; ii < list->size; ii++)
|
||||
{
|
||||
vc_container_assert(list->comparator(entry_ptr, entry_ptr + entry_size) <= 0);
|
||||
entry_ptr += entry_size;
|
||||
}
|
||||
}
|
102
gfx/include/userland/containers/core/containers_list.h
Normal file
102
gfx/include/userland/containers/core/containers_list.h
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _VC_CONTAINERS_LIST_H_
|
||||
#define _VC_CONTAINERS_LIST_H_
|
||||
|
||||
#include "containers/containers.h"
|
||||
|
||||
/** List entry comparison prototype.
|
||||
* Returns zero if items at a and b match, positive if a is "bigger" than b and
|
||||
* negative if a is "smaller" than b. */
|
||||
typedef int (*VC_CONTAINERS_LIST_COMPARATOR_T)(const void *a, const void *b);
|
||||
|
||||
/** Sorted list type.
|
||||
* Storage type providing efficient insertion and search via binary sub-division. */
|
||||
typedef struct vc_containers_list_tag
|
||||
{
|
||||
uint32_t size; /**< Number of defined entries in list */
|
||||
uint32_t capacity; /**< Capacity of list, in entries, or zero for read-only */
|
||||
size_t entry_size; /**< Size of one entry, in bytes */
|
||||
VC_CONTAINERS_LIST_COMPARATOR_T comparator; /**< Entry comparison function */
|
||||
void *entries; /**< Pointer to array of entries */
|
||||
} VC_CONTAINERS_LIST_T;
|
||||
|
||||
/** Macro to generate a static, read-only list from an array and comparator */
|
||||
#define VC_CONTAINERS_STATIC_LIST(L, A, C) static VC_CONTAINERS_LIST_T L = { countof(A), 0, sizeof(*(A)), (VC_CONTAINERS_LIST_COMPARATOR_T)(C), A }
|
||||
|
||||
|
||||
/** Create an empty list.
|
||||
* The list is created based on the details provided, minimum capacity one entry.
|
||||
*
|
||||
* \param The initial capacity in entries.
|
||||
* \param entry_size The size of each entry, in bytes.
|
||||
* \param comparator A function for comparing two entries.
|
||||
* \return The new list or NULL. */
|
||||
VC_CONTAINERS_LIST_T *vc_containers_list_create(uint32_t capacity, size_t entry_size, VC_CONTAINERS_LIST_COMPARATOR_T comparator);
|
||||
|
||||
/** Destroy a list.
|
||||
* Has no effect on a static list.
|
||||
*
|
||||
* \param list The list to be destroyed. */
|
||||
void vc_containers_list_destroy(VC_CONTAINERS_LIST_T *list);
|
||||
|
||||
/** Reset a list to be empty.
|
||||
* Has no effect on a static list.
|
||||
*
|
||||
* \param list The list to be reset. */
|
||||
void vc_containers_list_reset(VC_CONTAINERS_LIST_T *list);
|
||||
|
||||
/** Insert an entry into the list.
|
||||
*
|
||||
* \param list The list.
|
||||
* \param new_entry The new entry to be inserted.
|
||||
* \param allow_duplicates Determines whether to insert or overwrite if there
|
||||
* is an existing matching entry.
|
||||
* \return True if the entry has successfully been inserted, false if the list
|
||||
* needed to be enlarged and the memory allocation failed. */
|
||||
bool vc_containers_list_insert(VC_CONTAINERS_LIST_T *list, void *new_entry, bool allow_duplicates);
|
||||
|
||||
/** Find an entry in the list and fill in the result.
|
||||
* Searches for an entry in the list using the comparator and if found
|
||||
* overwrites the one passed in with the one found.
|
||||
*
|
||||
* \param list The list to search.
|
||||
* \param entry An entry with enough defined to find it in the list, filled in
|
||||
* with the rest if found.
|
||||
* \return True if found, false if not. */
|
||||
bool vc_containers_list_find_entry(const VC_CONTAINERS_LIST_T *list, void *entry);
|
||||
|
||||
/** Validates a list pointer.
|
||||
* Fields and contents of a list are checked and asserted to be correct. With a
|
||||
* large list this may be slow, so it is recommended only to call this in debug
|
||||
* builds.
|
||||
*
|
||||
* \param list The list to be validated. */
|
||||
void vc_containers_list_validate(const VC_CONTAINERS_LIST_T *list);
|
||||
|
||||
#endif /* _VC_CONTAINERS_LIST_H_ */
|
436
gfx/include/userland/containers/core/containers_loader.c
Normal file
436
gfx/include/userland/containers/core/containers_loader.c
Normal file
@ -0,0 +1,436 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "containers/core/containers_private.h"
|
||||
#include "containers/core/containers_loader.h"
|
||||
|
||||
#if !defined(ENABLE_CONTAINERS_STANDALONE)
|
||||
#include "vcos_dlfcn.h"
|
||||
#define DL_SUFFIX VCOS_SO_EXT
|
||||
#ifndef DL_PATH_PREFIX
|
||||
#define DL_PATH_PREFIX ""
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/******************************************************************************
|
||||
Type definitions.
|
||||
******************************************************************************/
|
||||
|
||||
typedef VC_CONTAINER_STATUS_T (*VC_CONTAINER_READER_OPEN_FUNC_T)(VC_CONTAINER_T *);
|
||||
typedef VC_CONTAINER_STATUS_T (*VC_CONTAINER_WRITER_OPEN_FUNC_T)(VC_CONTAINER_T *);
|
||||
|
||||
/******************************************************************************
|
||||
Prototypes for local functions
|
||||
******************************************************************************/
|
||||
|
||||
static void reset_context(VC_CONTAINER_T *p_ctx);
|
||||
static VC_CONTAINER_READER_OPEN_FUNC_T load_library(void **handle, const char *name, const char *ext, int read);
|
||||
static void unload_library(void *handle);
|
||||
static VC_CONTAINER_READER_OPEN_FUNC_T load_reader(void **handle, const char *name);
|
||||
static VC_CONTAINER_READER_OPEN_FUNC_T load_writer(void **handle, const char *name);
|
||||
static VC_CONTAINER_READER_OPEN_FUNC_T load_metadata_reader(void **handle, const char *name);
|
||||
static const char* container_for_fileext(const char *fileext);
|
||||
|
||||
/********************************************************************************
|
||||
List of supported containers
|
||||
********************************************************************************/
|
||||
|
||||
static const char *readers[] =
|
||||
{"mp4", "asf", "avi", "mkv", "wav", "flv", "simple", "rawvideo", "mpga", "ps", "rtp", "rtsp", "rcv", "rv9", "qsynth", "binary", 0};
|
||||
static const char *writers[] =
|
||||
{"mp4", "asf", "avi", "binary", "simple", "rawvideo", 0};
|
||||
static const char *metadata_readers[] =
|
||||
{"id3", 0};
|
||||
|
||||
#if defined(ENABLE_CONTAINERS_STANDALONE)
|
||||
VC_CONTAINER_STATUS_T asf_reader_open( VC_CONTAINER_T * );
|
||||
VC_CONTAINER_STATUS_T avi_reader_open( VC_CONTAINER_T * );
|
||||
VC_CONTAINER_STATUS_T avi_writer_open( VC_CONTAINER_T * );
|
||||
VC_CONTAINER_STATUS_T mp4_reader_open( VC_CONTAINER_T * );
|
||||
VC_CONTAINER_STATUS_T mp4_writer_open( VC_CONTAINER_T * );
|
||||
VC_CONTAINER_STATUS_T mpga_reader_open( VC_CONTAINER_T * );
|
||||
VC_CONTAINER_STATUS_T mkv_reader_open( VC_CONTAINER_T * );
|
||||
VC_CONTAINER_STATUS_T wav_reader_open( VC_CONTAINER_T * );
|
||||
VC_CONTAINER_STATUS_T flv_reader_open( VC_CONTAINER_T * );
|
||||
VC_CONTAINER_STATUS_T ps_reader_open( VC_CONTAINER_T * );
|
||||
VC_CONTAINER_STATUS_T rtp_reader_open( VC_CONTAINER_T * );
|
||||
VC_CONTAINER_STATUS_T rtsp_reader_open( VC_CONTAINER_T * );
|
||||
VC_CONTAINER_STATUS_T binary_reader_open( VC_CONTAINER_T * );
|
||||
VC_CONTAINER_STATUS_T binary_writer_open( VC_CONTAINER_T * );
|
||||
VC_CONTAINER_STATUS_T rcv_reader_open( VC_CONTAINER_T * );
|
||||
VC_CONTAINER_STATUS_T rv9_reader_open( VC_CONTAINER_T * );
|
||||
VC_CONTAINER_STATUS_T qsynth_reader_open( VC_CONTAINER_T * );
|
||||
VC_CONTAINER_STATUS_T simple_reader_open( VC_CONTAINER_T * );
|
||||
VC_CONTAINER_STATUS_T simple_writer_open( VC_CONTAINER_T * );
|
||||
VC_CONTAINER_STATUS_T rawvideo_reader_open( VC_CONTAINER_T * );
|
||||
VC_CONTAINER_STATUS_T rawvideo_writer_open( VC_CONTAINER_T * );
|
||||
|
||||
VC_CONTAINER_STATUS_T id3_metadata_reader_open( VC_CONTAINER_T * );
|
||||
|
||||
static struct
|
||||
{
|
||||
const char *name;
|
||||
VC_CONTAINER_READER_OPEN_FUNC_T func;
|
||||
} reader_entry_points[] =
|
||||
{
|
||||
{"asf", &asf_reader_open},
|
||||
{"avi", &avi_reader_open},
|
||||
{"mpga", &mpga_reader_open},
|
||||
{"mkv", &mkv_reader_open},
|
||||
{"wav", &wav_reader_open},
|
||||
{"mp4", &mp4_reader_open},
|
||||
{"flv", &flv_reader_open},
|
||||
{"ps", &ps_reader_open},
|
||||
{"binary", &binary_reader_open},
|
||||
{"rtp", &rtp_reader_open},
|
||||
{"rtsp", &rtsp_reader_open},
|
||||
{"rcv", &rcv_reader_open},
|
||||
{"rv9", &rv9_reader_open},
|
||||
{"qsynth", &qsynth_reader_open},
|
||||
{"simple", &simple_reader_open},
|
||||
{"rawvideo", &rawvideo_reader_open},
|
||||
{0, 0}
|
||||
};
|
||||
|
||||
static struct
|
||||
{
|
||||
const char *name;
|
||||
VC_CONTAINER_READER_OPEN_FUNC_T func;
|
||||
} metadata_reader_entry_points[] =
|
||||
{
|
||||
{"id3", &id3_metadata_reader_open},
|
||||
{0, 0}
|
||||
};
|
||||
|
||||
static struct
|
||||
{
|
||||
const char *name;
|
||||
VC_CONTAINER_WRITER_OPEN_FUNC_T func;
|
||||
} writer_entry_points[] =
|
||||
{
|
||||
{"avi", &avi_writer_open},
|
||||
{"mp4", &mp4_writer_open},
|
||||
{"binary", &binary_writer_open},
|
||||
{"simple", &simple_writer_open},
|
||||
{"rawvideo", &rawvideo_writer_open},
|
||||
{0, 0}
|
||||
};
|
||||
#endif /* defined(ENABLE_CONTAINERS_STANDALONE) */
|
||||
|
||||
/** Table describing the mapping between file extensions and container name.
|
||||
This is only used as optimisation to decide which container to try first.
|
||||
Entries where the file extension and container have the same name can be omitted. */
|
||||
static const struct {
|
||||
const char *extension;
|
||||
const char *container;
|
||||
} extension_container_mapping[] =
|
||||
{
|
||||
{ "wma", "asf" },
|
||||
{ "wmv", "asf" },
|
||||
{ "mov", "mp4" },
|
||||
{ "3gp", "mp4" },
|
||||
{ "mp2", "mpga" },
|
||||
{ "mp3", "mpga" },
|
||||
{ "webm", "mkv" },
|
||||
{ "mid", "qsynth" },
|
||||
{ "mld", "qsynth" },
|
||||
{ "mmf", "qsynth" },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
/********************************************************************************
|
||||
Public functions
|
||||
********************************************************************************/
|
||||
VC_CONTAINER_STATUS_T vc_container_load_reader(VC_CONTAINER_T *p_ctx, const char *fileext)
|
||||
{
|
||||
const char *name;
|
||||
void *handle = NULL;
|
||||
VC_CONTAINER_READER_OPEN_FUNC_T func;
|
||||
VC_CONTAINER_STATUS_T status;
|
||||
unsigned int i;
|
||||
int64_t offset;
|
||||
|
||||
vc_container_assert(p_ctx && !p_ctx->priv->module_handle);
|
||||
|
||||
/* FIXME: the missing part here is code that reads a configuration or
|
||||
searches the filesystem for container libraries. Instead, we currently
|
||||
rely on static arrays i.e. 'readers', 'writers', etc. */
|
||||
|
||||
/* Before trying proper container readers, iterate through metadata
|
||||
readers to parse tags concatenated to start/end of stream */
|
||||
for(i = 0; metadata_readers[i]; i++)
|
||||
{
|
||||
if ((func = load_metadata_reader(&handle, metadata_readers[i])) != NULL)
|
||||
{
|
||||
status = (*func)(p_ctx);
|
||||
if(!status && p_ctx->priv->pf_close) p_ctx->priv->pf_close(p_ctx);
|
||||
reset_context(p_ctx);
|
||||
unload_library(handle);
|
||||
if(status == VC_CONTAINER_SUCCESS) break;
|
||||
if (status != VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED) goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/* Store the current position, in case any containers don't leave the stream
|
||||
at the start, and the IO layer can cope with the seek */
|
||||
offset = p_ctx->priv->io->offset;
|
||||
|
||||
/* Now move to containers, try to find a readers using the file extension to name
|
||||
mapping first */
|
||||
if (fileext && (name = container_for_fileext(fileext)) != NULL && (func = load_reader(&handle, name)) != NULL)
|
||||
{
|
||||
status = (*func)(p_ctx);
|
||||
if(status == VC_CONTAINER_SUCCESS) goto success;
|
||||
unload_library(handle);
|
||||
if (status != VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED) goto error;
|
||||
}
|
||||
|
||||
/* If there was no suitable mapping, iterate through all readers. */
|
||||
for(i = 0; readers[i]; i++)
|
||||
{
|
||||
if ((func = load_reader(&handle, readers[i])) != NULL)
|
||||
{
|
||||
if(vc_container_io_seek(p_ctx->priv->io, offset) != VC_CONTAINER_SUCCESS)
|
||||
{
|
||||
unload_library(handle);
|
||||
goto error;
|
||||
}
|
||||
|
||||
status = (*func)(p_ctx);
|
||||
if(status == VC_CONTAINER_SUCCESS) goto success;
|
||||
reset_context(p_ctx);
|
||||
unload_library(handle);
|
||||
if (status != VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED) goto error;
|
||||
}
|
||||
}
|
||||
|
||||
error:
|
||||
return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
|
||||
success:
|
||||
p_ctx->priv->module_handle = handle;
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_CONTAINER_STATUS_T vc_container_load_writer(VC_CONTAINER_T *p_ctx, const char *fileext)
|
||||
{
|
||||
const char *name;
|
||||
void *handle = NULL;
|
||||
VC_CONTAINER_WRITER_OPEN_FUNC_T func;
|
||||
VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_FAILED;
|
||||
unsigned int i;
|
||||
|
||||
vc_container_assert(p_ctx && !p_ctx->priv->module_handle);
|
||||
|
||||
/* Do we have a container mapping for this file extension? */
|
||||
if ((name = container_for_fileext(fileext)) != NULL && (func = load_writer(&handle, name)) != NULL)
|
||||
{
|
||||
status = (*func)(p_ctx);
|
||||
if(status == VC_CONTAINER_SUCCESS) goto success;
|
||||
unload_library(handle);
|
||||
if (status != VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED) goto error;
|
||||
}
|
||||
|
||||
/* If there was no suitable mapping, iterate through all writers. */
|
||||
for(i = 0; writers[i]; i++)
|
||||
{
|
||||
if ((func = load_writer(&handle, writers[i])) != NULL)
|
||||
{
|
||||
status = (*func)(p_ctx);
|
||||
if(status == VC_CONTAINER_SUCCESS) goto success;
|
||||
unload_library(handle);
|
||||
if (status != VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED) goto error;
|
||||
}
|
||||
}
|
||||
|
||||
error:
|
||||
return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
|
||||
success:
|
||||
p_ctx->priv->module_handle = handle;
|
||||
return status;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
void vc_container_unload(VC_CONTAINER_T *p_ctx)
|
||||
{
|
||||
if (p_ctx->priv->module_handle)
|
||||
{
|
||||
unload_library(p_ctx->priv->module_handle);
|
||||
p_ctx->priv->module_handle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
Local Functions
|
||||
******************************************************************************/
|
||||
static void reset_context(VC_CONTAINER_T *p_ctx)
|
||||
{
|
||||
vc_container_assert(p_ctx);
|
||||
|
||||
p_ctx->capabilities = 0;
|
||||
p_ctx->tracks = NULL;
|
||||
p_ctx->tracks_num = 0;
|
||||
p_ctx->drm = NULL;
|
||||
p_ctx->priv->module = NULL;
|
||||
p_ctx->priv->pf_close = NULL;
|
||||
p_ctx->priv->pf_read = NULL;
|
||||
p_ctx->priv->pf_write = NULL;
|
||||
p_ctx->priv->pf_seek = NULL;
|
||||
p_ctx->priv->pf_control = NULL;
|
||||
p_ctx->priv->tmp_io = NULL;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_READER_OPEN_FUNC_T load_reader(void **handle, const char *name)
|
||||
{
|
||||
return load_library(handle, name, NULL, 1);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_READER_OPEN_FUNC_T load_writer(void **handle, const char *name)
|
||||
{
|
||||
return load_library(handle, name, NULL, 0);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_READER_OPEN_FUNC_T load_metadata_reader(void **handle, const char *name)
|
||||
{
|
||||
#define DL_PREFIX_METADATA "metadata_"
|
||||
return load_library(handle, name, DL_PREFIX_METADATA, 1);
|
||||
}
|
||||
|
||||
#if !defined(ENABLE_CONTAINERS_STANDALONE)
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_READER_OPEN_FUNC_T load_library(void **handle, const char *name, const char *ext, int read)
|
||||
{
|
||||
#define DL_PREFIX_RD "reader_"
|
||||
#define DL_PREFIX_WR "writer_"
|
||||
const char *entrypt_read = {"reader_open"};
|
||||
const char *entrypt_write = {"writer_open"};
|
||||
char *dl_name, *entrypt_name;
|
||||
void *dl_handle;
|
||||
VC_CONTAINER_READER_OPEN_FUNC_T func = NULL;
|
||||
unsigned dl_size, ep_size, name_len = strlen(name) + (ext ? strlen(ext) : 0);
|
||||
|
||||
vc_container_assert(read == 0 || read == 1);
|
||||
|
||||
dl_size = strlen(DL_PATH_PREFIX) + MAX(strlen(DL_PREFIX_RD), strlen(DL_PREFIX_WR)) + name_len + strlen(DL_SUFFIX) + 1;
|
||||
if ((dl_name = malloc(dl_size)) == NULL)
|
||||
return NULL;
|
||||
|
||||
ep_size = name_len + 1 + MAX(strlen(entrypt_read), strlen(entrypt_write)) + 1;
|
||||
if ((entrypt_name = malloc(ep_size)) == NULL)
|
||||
{
|
||||
free(dl_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
snprintf(dl_name, dl_size, "%s%s%s%s%s", DL_PATH_PREFIX, read ? DL_PREFIX_RD : DL_PREFIX_WR, ext ? ext : "", name, DL_SUFFIX);
|
||||
snprintf(entrypt_name, ep_size, "%s_%s%s", name, ext ? ext : "", read ? entrypt_read : entrypt_write);
|
||||
|
||||
if ( (dl_handle = vcos_dlopen(dl_name, VCOS_DL_NOW)) != NULL )
|
||||
{
|
||||
/* Try generic entrypoint name before the mangled, full name */
|
||||
func = (VC_CONTAINER_READER_OPEN_FUNC_T)vcos_dlsym(dl_handle, read ? entrypt_read : entrypt_write);
|
||||
#if !defined(__VIDEOCORE__) /* The following would be pointless on MW/VideoCore */
|
||||
if (!func) func = (VC_CONTAINER_READER_OPEN_FUNC_T)vcos_dlsym(dl_handle, entrypt_name);
|
||||
#endif
|
||||
/* Only return handle if symbol found */
|
||||
if (func)
|
||||
*handle = dl_handle;
|
||||
else
|
||||
vcos_dlclose(dl_handle);
|
||||
}
|
||||
|
||||
free(entrypt_name);
|
||||
free(dl_name);
|
||||
return func;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static void unload_library(void *handle)
|
||||
{
|
||||
vcos_dlclose(handle);
|
||||
}
|
||||
|
||||
#else /* !defined(ENABLE_CONTAINERS_STANDALONE) */
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_READER_OPEN_FUNC_T load_library(void **handle, const char *name, const char *ext, int read)
|
||||
{
|
||||
int i;
|
||||
VC_CONTAINER_PARAM_UNUSED(handle);
|
||||
VC_CONTAINER_PARAM_UNUSED(ext);
|
||||
|
||||
if (read)
|
||||
{
|
||||
for (i = 0; reader_entry_points[i].name; i++)
|
||||
if (!strcasecmp(reader_entry_points[i].name, name))
|
||||
return reader_entry_points[i].func;
|
||||
|
||||
for (i = 0; metadata_reader_entry_points[i].name; i++)
|
||||
if (!strcasecmp(metadata_reader_entry_points[i].name, name))
|
||||
return metadata_reader_entry_points[i].func;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; writer_entry_points[i].name; i++)
|
||||
if (!strcasecmp(writer_entry_points[i].name, name))
|
||||
return writer_entry_points[i].func;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static void unload_library(void *handle)
|
||||
{
|
||||
(void)handle;
|
||||
}
|
||||
|
||||
#endif /* !defined(ENABLE_CONTAINERS_STANDALONE) */
|
||||
|
||||
/*****************************************************************************/
|
||||
static const char* container_for_fileext(const char *fileext)
|
||||
{
|
||||
int i;
|
||||
|
||||
for( i = 0; fileext && extension_container_mapping[i].extension; i++ )
|
||||
{
|
||||
if (!strcasecmp( fileext, extension_container_mapping[i].extension ))
|
||||
return extension_container_mapping[i].container;
|
||||
}
|
||||
|
||||
return fileext;
|
||||
}
|
41
gfx/include/userland/containers/core/containers_loader.h
Normal file
41
gfx/include/userland/containers/core/containers_loader.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef VC_CONTAINERS_LOADER_H
|
||||
#define VC_CONTAINERS_LOADER_H
|
||||
|
||||
/** Find and attempt to load & open reader, 'fileext' is a hint that can be used
|
||||
to speed up loading. */
|
||||
VC_CONTAINER_STATUS_T vc_container_load_reader(VC_CONTAINER_T *p_ctx, const char *fileext);
|
||||
|
||||
/** Find and attempt to load & open writer, 'fileext' is a hint used to help in
|
||||
selecting the appropriate container format. */
|
||||
VC_CONTAINER_STATUS_T vc_container_load_writer(VC_CONTAINER_T *p_ctx, const char *fileext);
|
||||
|
||||
void vc_container_unload(VC_CONTAINER_T *p_ctx);
|
||||
|
||||
#endif /* VC_CONTAINERS_LOADER_H */
|
111
gfx/include/userland/containers/core/containers_logging.c
Normal file
111
gfx/include/userland/containers/core/containers_logging.c
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include "containers/containers.h"
|
||||
#include "containers/core/containers_private.h"
|
||||
#include "containers/core/containers_logging.h"
|
||||
|
||||
#ifndef ENABLE_CONTAINERS_STANDALONE
|
||||
# include "vcos.h"
|
||||
#endif
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#define LOG_TAG "ContainersCore"
|
||||
#include <cutils/log.h>
|
||||
#endif
|
||||
|
||||
/* Default verbosity that will be inherited by containers */
|
||||
static uint32_t default_verbosity_mask = VC_CONTAINER_LOG_ALL;
|
||||
|
||||
/* By default log everything that's not associated with a container context */
|
||||
static uint32_t verbosity_mask = VC_CONTAINER_LOG_ALL;
|
||||
|
||||
void vc_container_log_set_default_verbosity(uint32_t mask)
|
||||
{
|
||||
default_verbosity_mask = mask;
|
||||
}
|
||||
|
||||
uint32_t vc_container_log_get_default_verbosity(void)
|
||||
{
|
||||
return default_verbosity_mask;
|
||||
}
|
||||
|
||||
void vc_container_log_set_verbosity(VC_CONTAINER_T *ctx, uint32_t mask)
|
||||
{
|
||||
if(!ctx) verbosity_mask = mask;
|
||||
else ctx->priv->verbosity = mask;
|
||||
}
|
||||
|
||||
void vc_container_log(VC_CONTAINER_T *ctx, VC_CONTAINER_LOG_TYPE_T type, const char *format, ...)
|
||||
{
|
||||
uint32_t verbosity = ctx ? ctx->priv->verbosity : verbosity_mask;
|
||||
va_list args;
|
||||
|
||||
// Optimise out the call to vc_container_log_vargs etc. when it won't do anything.
|
||||
if(!(type & verbosity)) return;
|
||||
|
||||
va_start( args, format );
|
||||
vc_container_log_vargs(ctx, type, format, args);
|
||||
va_end( args );
|
||||
}
|
||||
|
||||
void vc_container_log_vargs(VC_CONTAINER_T *ctx, VC_CONTAINER_LOG_TYPE_T type, const char *format, va_list args)
|
||||
{
|
||||
uint32_t verbosity = ctx ? ctx->priv->verbosity : verbosity_mask;
|
||||
|
||||
// If the verbosity is such that the type doesn't need logging quit now.
|
||||
if(!(type & verbosity)) return;
|
||||
|
||||
#ifdef __ANDROID__
|
||||
{
|
||||
// Default to Android's "verbose" level (doesn't usually come out)
|
||||
android_LogPriority logLevel = ANDROID_LOG_VERBOSE;
|
||||
|
||||
// Where type suggest a higher level is required update logLevel.
|
||||
// (Usually type contains only 1 bit as set by the LOG_DEBUG, LOG_ERROR or LOG_INFO macros)
|
||||
if (type & VC_CONTAINER_LOG_ERROR)
|
||||
logLevel = ANDROID_LOG_ERROR;
|
||||
else if (type & VC_CONTAINER_LOG_INFO)
|
||||
logLevel = ANDROID_LOG_INFO;
|
||||
else if (type & VC_CONTAINER_LOG_DEBUG)
|
||||
logLevel = ANDROID_LOG_DEBUG;
|
||||
|
||||
// Actually put the message out.
|
||||
LOG_PRI_VA(logLevel, LOG_TAG, format, args);
|
||||
}
|
||||
#else
|
||||
#ifndef ENABLE_CONTAINERS_STANDALONE
|
||||
vcos_vlog(format, args);
|
||||
#else
|
||||
vprintf(format, args); printf("\n");
|
||||
fflush(0);
|
||||
#endif
|
||||
#endif
|
||||
}
|
77
gfx/include/userland/containers/core/containers_logging.h
Normal file
77
gfx/include/userland/containers/core/containers_logging.h
Normal file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef VC_CONTAINERS_LOGGING_H
|
||||
#define VC_CONTAINERS_LOGGING_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** \file containers_logging.h
|
||||
* Logging API used by container readers and writers
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
VC_CONTAINER_LOG_ERROR = 0x01,
|
||||
VC_CONTAINER_LOG_INFO = 0x02,
|
||||
VC_CONTAINER_LOG_DEBUG = 0x04,
|
||||
VC_CONTAINER_LOG_FORMAT = 0x08,
|
||||
VC_CONTAINER_LOG_ALL = 0xFF
|
||||
} VC_CONTAINER_LOG_TYPE_T;
|
||||
|
||||
void vc_container_log(VC_CONTAINER_T *ctx, VC_CONTAINER_LOG_TYPE_T type, const char *format, ...);
|
||||
void vc_container_log_vargs(VC_CONTAINER_T *ctx, VC_CONTAINER_LOG_TYPE_T type, const char *format, va_list args);
|
||||
void vc_container_log_set_verbosity(VC_CONTAINER_T *ctx, uint32_t mask);
|
||||
void vc_container_log_set_default_verbosity(uint32_t mask);
|
||||
uint32_t vc_container_log_get_default_verbosity(void);
|
||||
|
||||
#define ENABLE_CONTAINER_LOG_ERROR
|
||||
#define ENABLE_CONTAINER_LOG_INFO
|
||||
|
||||
#ifdef ENABLE_CONTAINER_LOG_DEBUG
|
||||
# define LOG_DEBUG(ctx, ...) vc_container_log(ctx, VC_CONTAINER_LOG_DEBUG, __VA_ARGS__)
|
||||
#else
|
||||
# define LOG_DEBUG(ctx, ...) VC_CONTAINER_PARAM_UNUSED(ctx)
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_CONTAINER_LOG_ERROR
|
||||
# define LOG_ERROR(ctx, ...) vc_container_log(ctx, VC_CONTAINER_LOG_ERROR, __VA_ARGS__)
|
||||
#else
|
||||
# define LOG_ERROR(ctx, ...) VC_CONTAINER_PARAM_UNUSED(ctx)
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_CONTAINER_LOG_INFO
|
||||
# define LOG_INFO(ctx, ...) vc_container_log(ctx, VC_CONTAINER_LOG_INFO, __VA_ARGS__)
|
||||
#else
|
||||
# define LOG_INFO(ctx, ...) VC_CONTAINER_PARAM_UNUSED(ctx)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* VC_CONTAINERS_LOGGING_H */
|
183
gfx/include/userland/containers/core/containers_private.h
Normal file
183
gfx/include/userland/containers/core/containers_private.h
Normal file
@ -0,0 +1,183 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef VC_CONTAINERS_PRIVATE_H
|
||||
#define VC_CONTAINERS_PRIVATE_H
|
||||
|
||||
/** \file containers_private.h
|
||||
* Private interface for container readers and writers
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include "containers/containers.h"
|
||||
#include "containers/core/containers_common.h"
|
||||
#include "containers/core/containers_io.h"
|
||||
#include "containers/core/containers_filters.h"
|
||||
#include "containers/packetizers.h"
|
||||
#include "containers/core/containers_uri.h"
|
||||
|
||||
#define URI_MAX_LEN 256
|
||||
|
||||
/** \defgroup VcContainerModuleApi Container Module API
|
||||
* Private interface for modules implementing container readers and writers */
|
||||
/* @{ */
|
||||
|
||||
/** Track context private to the container reader / writer instance. This private context is used to
|
||||
* store data which shouldn't be exported by the public API. */
|
||||
typedef struct VC_CONTAINER_TRACK_PRIVATE_T
|
||||
{
|
||||
/** Pointer to the private data of the container module in use */
|
||||
struct VC_CONTAINER_TRACK_MODULE_T *module;
|
||||
|
||||
/** Pointer to the allocated buffer for the track extradata */
|
||||
uint8_t *extradata;
|
||||
/** Size of the allocated buffer for the track extradata */
|
||||
uint32_t extradata_size;
|
||||
|
||||
/** Pointer to the allocated buffer for the track DRM data*/
|
||||
uint8_t *drmdata;
|
||||
/** Size of the allocated buffer for the track DRM data */
|
||||
uint32_t drmdata_size;
|
||||
|
||||
/** Packetizer used by this track */
|
||||
VC_PACKETIZER_T *packetizer;
|
||||
|
||||
} VC_CONTAINER_TRACK_PRIVATE_T;
|
||||
|
||||
/** Context private to the container reader / writer instance. This private context is used to
|
||||
* store data which shouldn't be exported by the public API. */
|
||||
typedef struct VC_CONTAINER_PRIVATE_T
|
||||
{
|
||||
/** Pointer to the container i/o instance used to read / write to the container */
|
||||
struct VC_CONTAINER_IO_T *io;
|
||||
/** Pointer to the private data of the container module in use */
|
||||
struct VC_CONTAINER_MODULE_T *module;
|
||||
|
||||
/** Reads a data packet from a container reader.
|
||||
* By default, the reader will read whatever packet comes next in the container and update the
|
||||
* given \ref VC_CONTAINER_PACKET_T structure with this packet's information.
|
||||
* This behaviour can be changed using the \ref VC_CONTAINER_READ_FLAGS_T.\n
|
||||
* \ref VC_CONTAINER_READ_FLAG_INFO will instruct the reader to only return information on the
|
||||
* following packet but not its actual data. The data can be retreived later by issuing another
|
||||
* read request.
|
||||
* \ref VC_CONTAINER_READ_FLAG_FORCE_TRACK will force the reader to read the next packet for the
|
||||
* selected track (as present in the \ref VC_CONTAINER_PACKET_T structure) instead of defaulting
|
||||
* to reading the packet which comes next in the container.
|
||||
* \ref VC_CONTAINER_READ_FLAG_SKIP will instruct the reader to skip the next packet. In this case
|
||||
* it isn't necessary for the caller to pass a pointer to a \ref VC_CONTAINER_PACKET_T structure
|
||||
* unless the \ref VC_CONTAINER_READ_FLAG_INFO is also given.
|
||||
* A combination of all these flags can be used.
|
||||
*
|
||||
* \param context Pointer to the context of the reader to use
|
||||
* \param packet Pointer to the VC_CONTAINER_PACKET_T structure describing the data packet
|
||||
* This needs to be partially filled before the call (buffer, buffer_size)
|
||||
* \param flags Flags controlling the read operation
|
||||
* \return the status of the operation
|
||||
*/
|
||||
VC_CONTAINER_STATUS_T (*pf_read)( VC_CONTAINER_T *context,
|
||||
VC_CONTAINER_PACKET_T *packet, VC_CONTAINER_READ_FLAGS_T flags );
|
||||
|
||||
/** Writes a data packet to a container writer.
|
||||
*
|
||||
* \param context Pointer to the context of the writer to use
|
||||
* \param packet Pointer to the VC_CONTAINER_PACKET_T structure describing the data packet
|
||||
* \return the status of the operation
|
||||
*/
|
||||
VC_CONTAINER_STATUS_T (*pf_write)( struct VC_CONTAINER_T *context,
|
||||
VC_CONTAINER_PACKET_T *packet );
|
||||
|
||||
/** Seek into a container reader.
|
||||
*
|
||||
* \param context Pointer to the context of the reader to use
|
||||
* \param offset Offset to seek to. Used as an input as well as output value.
|
||||
* \param mode Seeking mode requested.
|
||||
* \param flags Flags affecting the seeking operation.
|
||||
* \return the status of the operation
|
||||
*/
|
||||
VC_CONTAINER_STATUS_T (*pf_seek)( VC_CONTAINER_T *context, int64_t *offset,
|
||||
VC_CONTAINER_SEEK_MODE_T mode, VC_CONTAINER_SEEK_FLAGS_T flags);
|
||||
|
||||
/** Extensible control function for container readers and writers.
|
||||
* This function takes a variable number of arguments which will depend on the specific operation.
|
||||
*
|
||||
* \param context Pointer to the VC_CONTAINER_T context to use
|
||||
* \param operation The requested operation
|
||||
* \return the status of the operation
|
||||
*/
|
||||
VC_CONTAINER_STATUS_T (*pf_control)( VC_CONTAINER_T *context, VC_CONTAINER_CONTROL_T operation, va_list args );
|
||||
|
||||
/** Closes a container reader / writer module.
|
||||
*
|
||||
* \param context Pointer to the context of the instance to close
|
||||
* \return the status of the operation
|
||||
*/
|
||||
VC_CONTAINER_STATUS_T (*pf_close)( struct VC_CONTAINER_T *context );
|
||||
|
||||
/** Pointer to container filter instance used for DRM */
|
||||
struct VC_CONTAINER_FILTER_T *drm_filter;
|
||||
|
||||
/** Pointer to the container module code and symbols*/
|
||||
void *module_handle;
|
||||
|
||||
/** Maximum size of a stream that is being written.
|
||||
* This is set by the client using the control mechanism */
|
||||
int64_t max_size;
|
||||
|
||||
/** Pointer to the temp i/o instance used to write temporary data */
|
||||
struct VC_CONTAINER_IO_T *tmp_io;
|
||||
|
||||
/** Current status of the container (only used for writers to prevent trying to write
|
||||
* more data if one of the writes failed) */
|
||||
VC_CONTAINER_STATUS_T status;
|
||||
|
||||
/** Logging verbosity */
|
||||
uint32_t verbosity;
|
||||
|
||||
/** Uniform Resource Identifier */
|
||||
struct VC_URI_PARTS_T *uri;
|
||||
|
||||
/** Flag specifying whether one of the tracks is being packetized */
|
||||
bool packetizing;
|
||||
|
||||
/** Temporary packet structure used to feed data to the packetizer */
|
||||
VC_CONTAINER_PACKET_T packetizer_packet;
|
||||
|
||||
/** Temporary buffer used by the packetizer */
|
||||
uint8_t *packetizer_buffer;
|
||||
|
||||
} VC_CONTAINER_PRIVATE_T;
|
||||
|
||||
/* Internal functions */
|
||||
VC_CONTAINER_TRACK_T *vc_container_allocate_track( VC_CONTAINER_T *context, unsigned int extra_size );
|
||||
void vc_container_free_track( VC_CONTAINER_T *context, VC_CONTAINER_TRACK_T *track );
|
||||
VC_CONTAINER_STATUS_T vc_container_track_allocate_extradata( VC_CONTAINER_T *context,
|
||||
VC_CONTAINER_TRACK_T *p_track, unsigned int extra_size );
|
||||
VC_CONTAINER_STATUS_T vc_container_track_allocate_drmdata( VC_CONTAINER_T *context,
|
||||
VC_CONTAINER_TRACK_T *p_track, unsigned int size );
|
||||
|
||||
/* @} */
|
||||
|
||||
#endif /* VC_CONTAINERS_PRIVATE_H */
|
103
gfx/include/userland/containers/core/containers_time.h
Normal file
103
gfx/include/userland/containers/core/containers_time.h
Normal file
@ -0,0 +1,103 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef VC_CONTAINERS_TIME_H
|
||||
#define VC_CONTAINERS_TIME_H
|
||||
|
||||
/** \file
|
||||
* Utility functions to help with timestamping of elementary stream frames
|
||||
*/
|
||||
|
||||
typedef struct VC_CONTAINER_TIME_T
|
||||
{
|
||||
uint32_t samplerate_num;
|
||||
uint32_t samplerate_den;
|
||||
uint32_t time_base;
|
||||
|
||||
uint32_t remainder;
|
||||
|
||||
int64_t time;
|
||||
|
||||
} VC_CONTAINER_TIME_T;
|
||||
|
||||
/*****************************************************************************/
|
||||
STATIC_INLINE void vc_container_time_init( VC_CONTAINER_TIME_T *time, uint32_t time_base )
|
||||
{
|
||||
time->samplerate_num = 0;
|
||||
time->samplerate_den = 0;
|
||||
time->remainder = 0;
|
||||
time->time_base = time_base;
|
||||
time->time = VC_CONTAINER_TIME_UNKNOWN;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
STATIC_INLINE int64_t vc_container_time_get( VC_CONTAINER_TIME_T *time )
|
||||
{
|
||||
if (time->time == VC_CONTAINER_TIME_UNKNOWN || !time->samplerate_num || !time->samplerate_den)
|
||||
return VC_CONTAINER_TIME_UNKNOWN;
|
||||
return time->time + time->remainder * (int64_t)time->time_base * time->samplerate_den / time->samplerate_num;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
STATIC_INLINE void vc_container_time_set_samplerate( VC_CONTAINER_TIME_T *time, uint32_t samplerate_num, uint32_t samplerate_den )
|
||||
{
|
||||
if(time->samplerate_num == samplerate_num &&
|
||||
time->samplerate_den == samplerate_den)
|
||||
return;
|
||||
|
||||
/* We're changing samplerate, we need to reset our remainder */
|
||||
if(time->remainder)
|
||||
time->time = vc_container_time_get( time );
|
||||
time->remainder = 0;
|
||||
time->samplerate_num = samplerate_num;
|
||||
time->samplerate_den = samplerate_den;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
STATIC_INLINE void vc_container_time_set( VC_CONTAINER_TIME_T *time, int64_t new_time )
|
||||
{
|
||||
if (new_time == VC_CONTAINER_TIME_UNKNOWN)
|
||||
return;
|
||||
time->remainder = 0;
|
||||
time->time = new_time;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
STATIC_INLINE int64_t vc_container_time_add( VC_CONTAINER_TIME_T *time, uint32_t samples )
|
||||
{
|
||||
uint32_t increment;
|
||||
|
||||
if (time->time == VC_CONTAINER_TIME_UNKNOWN || !time->samplerate_num || !time->samplerate_den)
|
||||
return VC_CONTAINER_TIME_UNKNOWN;
|
||||
|
||||
samples += time->remainder;
|
||||
increment = samples * time->samplerate_den / time->samplerate_num;
|
||||
time->time += increment * time->time_base;
|
||||
time->remainder = samples - increment * time->samplerate_num / time->samplerate_den;
|
||||
return vc_container_time_get(time);
|
||||
}
|
||||
|
||||
#endif /* VC_CONTAINERS_TIME_H */
|
1120
gfx/include/userland/containers/core/containers_uri.c
Normal file
1120
gfx/include/userland/containers/core/containers_uri.c
Normal file
File diff suppressed because it is too large
Load Diff
241
gfx/include/userland/containers/core/containers_uri.h
Normal file
241
gfx/include/userland/containers/core/containers_uri.h
Normal file
@ -0,0 +1,241 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef VC_CONTAINERS_URI_H
|
||||
#define VC_CONTAINERS_URI_H
|
||||
|
||||
/** \file containers_uri.h
|
||||
* API for parsing and building URI strings as described in RFC3986.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "containers/containers.h"
|
||||
|
||||
typedef struct VC_URI_PARTS_T VC_URI_PARTS_T;
|
||||
|
||||
/** Create an empty URI structure.
|
||||
*
|
||||
* \return The new URI structure. */
|
||||
VC_URI_PARTS_T *vc_uri_create( void );
|
||||
|
||||
/** Destroy a URI structure.
|
||||
*
|
||||
* \param p_uri Pointer to a URI parts structure. */
|
||||
void vc_uri_release( VC_URI_PARTS_T *p_uri );
|
||||
|
||||
/** Clear a URI structure.
|
||||
* Any URI component strings held are released, but the structure itself is not.
|
||||
*
|
||||
* \param p_uri Pointer to a URI parts structure. */
|
||||
void vc_uri_clear( VC_URI_PARTS_T *p_uri );
|
||||
|
||||
/** Parses and unescapes a URI into the component parts.
|
||||
*
|
||||
* \param p_uri Pointer to a URI parts structure.
|
||||
* \param uri Pointer to a URI string to be parsed.
|
||||
* \return True if successful, false if not. */
|
||||
bool vc_uri_parse( VC_URI_PARTS_T *p_uri, const char *uri );
|
||||
|
||||
/** Builds the URI component parts into a URI string.
|
||||
* If buffer is NULL, or buffer_size is too small, nothing is written to the
|
||||
* buffer but the required string length is still returned. buffer_size must be
|
||||
* at least one more than the value returned.
|
||||
*
|
||||
* \param p_uri Pointer to a URI parts structure.
|
||||
* \param buffer Pointer to where the URI string is to be built, or NULL.
|
||||
* \param buffer_size Number of bytes available in the buffer.
|
||||
* \return The length of the URI string. */
|
||||
uint32_t vc_uri_build( const VC_URI_PARTS_T *p_uri, char *buffer, size_t buffer_size );
|
||||
|
||||
/** Retrieves the scheme of the URI.
|
||||
* The string is valid until either the scheme is changed or the URI is released.
|
||||
*
|
||||
* \param p_uri The parsed URI.
|
||||
* \return Pointer to the scheme string. */
|
||||
const char *vc_uri_scheme( const VC_URI_PARTS_T *p_uri );
|
||||
|
||||
/** Retrieves the userinfo of the URI.
|
||||
* The string is valid until either the userinfo is changed or the URI is released.
|
||||
*
|
||||
* \param p_uri The parsed URI.
|
||||
* \return Pointer to the userinfo string. */
|
||||
const char *vc_uri_userinfo( const VC_URI_PARTS_T *p_uri );
|
||||
|
||||
/** Retrieves the host of the URI.
|
||||
* The string is valid until either the host is changed or the URI is released.
|
||||
*
|
||||
* \param p_uri The parsed URI.
|
||||
* \return Pointer to the host string. */
|
||||
const char *vc_uri_host( const VC_URI_PARTS_T *p_uri );
|
||||
|
||||
/** Retrieves the port of the URI.
|
||||
* The string is valid until either the port is changed or the URI is released.
|
||||
*
|
||||
* \param p_uri The parsed URI.
|
||||
* \return Pointer to the port string. */
|
||||
const char *vc_uri_port( const VC_URI_PARTS_T *p_uri );
|
||||
|
||||
/** Retrieves the path of the URI.
|
||||
* The string is valid until either the path is changed or the URI is released.
|
||||
*
|
||||
* \param p_uri The parsed URI.
|
||||
* \return Pointer to the path string. */
|
||||
const char *vc_uri_path( const VC_URI_PARTS_T *p_uri );
|
||||
|
||||
/** Retrieves the extension part of the path of the URI.
|
||||
* The string is valid until either the path is changed or the URI is released.
|
||||
*
|
||||
* \param p_uri The parsed URI.
|
||||
* \return Pointer to the extension string. */
|
||||
const char *vc_uri_path_extension( const VC_URI_PARTS_T *p_uri );
|
||||
|
||||
/** Retrieves the fragment of the URI.
|
||||
* The string is valid until either the fragment is changed or the URI is released.
|
||||
*
|
||||
* \param p_uri The parsed URI.
|
||||
* \return Pointer to the fragment string. */
|
||||
const char *vc_uri_fragment( const VC_URI_PARTS_T *p_uri );
|
||||
|
||||
/** Returns the number of query name/value pairs stored.
|
||||
*
|
||||
* \param p_uri The parsed URI.
|
||||
* \return Number of queries stored. */
|
||||
uint32_t vc_uri_num_queries( const VC_URI_PARTS_T *p_uri );
|
||||
|
||||
/** Retrieves a given query's name and value
|
||||
* If either p_name or p_value are NULL, that part of the query is not returned,
|
||||
* otherwise it is set to the address of the string (which may itself be NULL).
|
||||
*
|
||||
* \param p_uri The parsed URI.
|
||||
* \param index Selects the query to get.
|
||||
* \param p_name Address of a string pointer to receive query name, or NULL.
|
||||
* \param p_value Address of a string pointer to receive query value, or NULL. */
|
||||
void vc_uri_query( const VC_URI_PARTS_T *p_uri, uint32_t index, const char **p_name, const char **p_value );
|
||||
|
||||
/** Finds a specific query in the array.
|
||||
* If p_index is NULL, then it is assumed the search should start at index 0,
|
||||
* otherwise the search will start at the specified index and the index will
|
||||
* be updated on return to point to the query which has been found.
|
||||
* If p_value is NULL, that part of the query is not returned,
|
||||
* otherwise it is set to the address of the value string (which may itself be NULL).
|
||||
*
|
||||
* \param p_uri Pointer to a URI parts structure.
|
||||
* \param p_index Index from which to start the search. May be NULL.
|
||||
* \param name Unescaped query name.
|
||||
* \param value Unescaped query value. May be NULL.
|
||||
* \return True if successful, false if not. */
|
||||
bool vc_uri_find_query( VC_URI_PARTS_T *p_uri, uint32_t *p_index, const char *name, const char **p_value );
|
||||
|
||||
/** Sets the scheme of the URI.
|
||||
* The string will be copied and stored in the URI, releasing and replacing
|
||||
* any existing string. If NULL is passed, any existing string shall simply be
|
||||
* released.
|
||||
*
|
||||
* \param p_uri The parsed URI.
|
||||
* \param scheme Pointer to the new scheme string, or NULL.
|
||||
* \return True if successful, false on memory allocation failure. */
|
||||
bool vc_uri_set_scheme( VC_URI_PARTS_T *p_uri, const char *scheme );
|
||||
|
||||
/** Sets the userinfo of the URI.
|
||||
* The string will be copied and stored in the URI, releasing and replacing
|
||||
* any existing string. If NULL is passed, any existing string shall simply be
|
||||
* released.
|
||||
*
|
||||
* \param p_uri The parsed URI.
|
||||
* \param userinfo Pointer to the new userinfo string, or NULL.
|
||||
* \return True if successful, false on memory allocation failure. */
|
||||
bool vc_uri_set_userinfo( VC_URI_PARTS_T *p_uri, const char *userinfo );
|
||||
|
||||
/** Sets the host of the URI.
|
||||
* The string will be copied and stored in the URI, releasing and replacing
|
||||
* any existing string. If NULL is passed, any existing string shall simply be
|
||||
* released.
|
||||
*
|
||||
* \param p_uri The parsed URI.
|
||||
* \param host Pointer to the new host string, or NULL.
|
||||
* \return True if successful, false on memory allocation failure. */
|
||||
bool vc_uri_set_host( VC_URI_PARTS_T *p_uri, const char *host );
|
||||
|
||||
/** Sets the port of the URI.
|
||||
* The string will be copied and stored in the URI, releasing and replacing
|
||||
* any existing string. If NULL is passed, any existing string shall simply be
|
||||
* released.
|
||||
*
|
||||
* \param p_uri The parsed URI.
|
||||
* \param port Pointer to the new port string, or NULL.
|
||||
* \return True if successful, false on memory allocation failure. */
|
||||
bool vc_uri_set_port( VC_URI_PARTS_T *p_uri, const char *port );
|
||||
|
||||
/** Sets the path of the URI.
|
||||
* The string will be copied and stored in the URI, releasing and replacing
|
||||
* any existing string. If NULL is passed, any existing string shall simply be
|
||||
* released.
|
||||
*
|
||||
* \param p_uri The parsed URI.
|
||||
* \param path Pointer to the new path string, or NULL.
|
||||
* \return True if successful, false on memory allocation failure. */
|
||||
bool vc_uri_set_path( VC_URI_PARTS_T *p_uri, const char *path );
|
||||
|
||||
/** Sets the fragment of the URI.
|
||||
* The string will be copied and stored in the URI, releasing and replacing
|
||||
* any existing string. If NULL is passed, any existing string shall simply be
|
||||
* released.
|
||||
*
|
||||
* \param p_uri The parsed URI.
|
||||
* \param fragment Pointer to the new fragment string, or NULL.
|
||||
* \return True if successful, false on memory allocation failure. */
|
||||
bool vc_uri_set_fragment( VC_URI_PARTS_T *p_uri, const char *fragment );
|
||||
|
||||
/** Adds an query to the array.
|
||||
* Note that the queries pointer may change after this function is called.
|
||||
* May fail due to memory allocation failure or invalid parameters.
|
||||
*
|
||||
* \param p_uri Pointer to a URI parts structure.
|
||||
* \param name Unescaped query name.
|
||||
* \param value Unescaped query value. May be NULL.
|
||||
* \return True if successful, false if not. */
|
||||
bool vc_uri_add_query( VC_URI_PARTS_T *p_uri, const char *name, const char *value );
|
||||
|
||||
/** Merge a base URI and a relative URI.
|
||||
* In general, where the relative URI does not have a given element, the
|
||||
* corresponding element from the base URI is used. See RFC1808.
|
||||
* The combined URI is left in relative_uri. If the function is unsuccessful,
|
||||
* the relative_uri may have been partially modified.
|
||||
*
|
||||
* \param base_uri Pointer to the base URI parts structure.
|
||||
* \param relative_uri Pointer to the relative URI parts structure.
|
||||
* \return True if successful, false if not. */
|
||||
bool vc_uri_merge( const VC_URI_PARTS_T *base_uri, VC_URI_PARTS_T *relative_uri );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* VC_CONTAINERS_URI_H */
|
366
gfx/include/userland/containers/core/containers_utils.c
Normal file
366
gfx/include/userland/containers/core/containers_utils.c
Normal file
@ -0,0 +1,366 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "containers/containers.h"
|
||||
#include "containers/core/containers_common.h"
|
||||
#include "containers/core/containers_utils.h"
|
||||
|
||||
/******************************************************************************
|
||||
Defines.
|
||||
******************************************************************************/
|
||||
#define BITMAPINFOHEADER_SIZE_MAX 40
|
||||
#define MAX_EXTENSION_SIZE 4
|
||||
|
||||
#define VC_CONTAINER_ES_FORMAT_MAGIC ((uint32_t)VC_FOURCC('m','a','g','f'))
|
||||
#define EXTRADATA_SIZE_DEFAULT 32
|
||||
#define EXTRADATA_SIZE_MAX (10*1024)
|
||||
|
||||
/*****************************************************************************/
|
||||
typedef struct VC_CONTAINER_ES_FORMAT_PRIVATE_T
|
||||
{
|
||||
VC_CONTAINER_ES_FORMAT_T format;
|
||||
VC_CONTAINER_ES_SPECIFIC_FORMAT_T type;
|
||||
|
||||
uint32_t magic;
|
||||
|
||||
unsigned int extradata_size;
|
||||
uint8_t *extradata;
|
||||
|
||||
uint8_t buffer[EXTRADATA_SIZE_DEFAULT];
|
||||
|
||||
} VC_CONTAINER_ES_FORMAT_PRIVATE_T;
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_CONTAINER_ES_FORMAT_T *vc_container_format_create(unsigned int extradata_size)
|
||||
{
|
||||
VC_CONTAINER_ES_FORMAT_PRIVATE_T *private;
|
||||
VC_CONTAINER_STATUS_T status;
|
||||
|
||||
private = malloc(sizeof(*private));
|
||||
if(!private) return 0;
|
||||
memset(private, 0, sizeof(*private));
|
||||
|
||||
private->magic = VC_CONTAINER_ES_FORMAT_MAGIC;
|
||||
private->format.type = (void *)&private->type;
|
||||
private->extradata_size = EXTRADATA_SIZE_DEFAULT;
|
||||
|
||||
status = vc_container_format_extradata_alloc(&private->format, extradata_size);
|
||||
if(status != VC_CONTAINER_SUCCESS)
|
||||
{
|
||||
free(private);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &private->format;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
void vc_container_format_delete(VC_CONTAINER_ES_FORMAT_T *format)
|
||||
{
|
||||
VC_CONTAINER_ES_FORMAT_PRIVATE_T *private = (VC_CONTAINER_ES_FORMAT_PRIVATE_T *)format;
|
||||
vc_container_assert(private->magic == VC_CONTAINER_ES_FORMAT_MAGIC);
|
||||
if(private->extradata) free(private->extradata);
|
||||
free(private);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_CONTAINER_STATUS_T vc_container_format_extradata_alloc(
|
||||
VC_CONTAINER_ES_FORMAT_T *format, unsigned int size)
|
||||
{
|
||||
VC_CONTAINER_ES_FORMAT_PRIVATE_T *private = (VC_CONTAINER_ES_FORMAT_PRIVATE_T *)format;
|
||||
vc_container_assert(private->magic == VC_CONTAINER_ES_FORMAT_MAGIC);
|
||||
|
||||
/* Sanity check the size requested */
|
||||
if(size > EXTRADATA_SIZE_MAX)
|
||||
return VC_CONTAINER_ERROR_CORRUPTED;
|
||||
|
||||
/* Allocate memory if needed */
|
||||
if(private->extradata_size < size)
|
||||
{
|
||||
if(private->extradata) free(private->extradata);
|
||||
private->extradata = malloc(size);
|
||||
if(!private->extradata)
|
||||
return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
|
||||
private->extradata_size = size;
|
||||
}
|
||||
|
||||
/* Set the fields in the actual format structure */
|
||||
if(private->extradata) private->format.extradata = private->extradata;
|
||||
else private->format.extradata = private->buffer;
|
||||
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_CONTAINER_STATUS_T vc_container_format_copy( VC_CONTAINER_ES_FORMAT_T *p_out,
|
||||
VC_CONTAINER_ES_FORMAT_T *p_in,
|
||||
unsigned int extra_buffer_size)
|
||||
{
|
||||
void *type = p_out->type;
|
||||
uint8_t *extradata = p_out->extradata;
|
||||
|
||||
/* Check we have a sufficient buffer to copy the extra data */
|
||||
if(p_in->extradata_size > extra_buffer_size ||
|
||||
(p_in->extradata_size && !p_out->extradata))
|
||||
return VC_CONTAINER_ERROR_BUFFER_TOO_SMALL;
|
||||
|
||||
*p_out->type = *p_in->type;
|
||||
*p_out = *p_in;
|
||||
p_out->type = type;
|
||||
p_out->extradata = extradata;
|
||||
if(p_in->extradata_size)
|
||||
memcpy(p_out->extradata, p_in->extradata, p_in->extradata_size);
|
||||
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int utf8_from_charset(const char *charset, char *out, unsigned int out_size,
|
||||
const void *in, unsigned int in_size)
|
||||
{
|
||||
unsigned int i;
|
||||
const uint16_t *in16 = (const uint16_t *)in;
|
||||
const uint8_t *in8 = (const uint8_t *)in;
|
||||
|
||||
if(out_size < 1) return 1;
|
||||
if(!strcmp(charset, "UTF16-LE")) goto utf16le;
|
||||
if(!strcmp(charset, "UTF8")) goto utf8;
|
||||
else return 1;
|
||||
|
||||
utf16le:
|
||||
for(i = 0; i < in_size / 2 && in16[i] && i < out_size - 1; i++)
|
||||
{
|
||||
out[i] = in16[i];
|
||||
}
|
||||
out[i] = 0;
|
||||
return 0;
|
||||
|
||||
utf8:
|
||||
for(i = 0; i < in_size && in8[i] && i < out_size - 1; i++)
|
||||
{
|
||||
out[i] = in8[i];
|
||||
}
|
||||
out[i] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
unsigned int vc_container_es_format_to_waveformatex(VC_CONTAINER_ES_FORMAT_T *format,
|
||||
uint8_t *buffer, unsigned int buffer_size)
|
||||
{
|
||||
uint16_t waveformat = codec_to_waveformat(format->codec);
|
||||
|
||||
if(format->es_type != VC_CONTAINER_ES_TYPE_AUDIO ||
|
||||
waveformat == WAVE_FORMAT_UNKNOWN) return 0;
|
||||
|
||||
if(!buffer) return format->extradata_size + 18;
|
||||
|
||||
if(buffer_size < format->extradata_size + 18) return 0;
|
||||
|
||||
/* Build a waveformatex header */
|
||||
buffer[0] = waveformat;
|
||||
buffer[1] = waveformat >> 8;
|
||||
buffer[2] = format->type->audio.channels;
|
||||
buffer[3] = 0;
|
||||
buffer[4] = (format->type->audio.sample_rate >> 0) & 0xFF;
|
||||
buffer[5] = (format->type->audio.sample_rate >> 8) & 0xFF;
|
||||
buffer[6] = (format->type->audio.sample_rate >> 16) & 0xFF;
|
||||
buffer[7] = (format->type->audio.sample_rate >> 24) & 0xFF;
|
||||
buffer[8] = (format->bitrate >> 3) & 0xFF;
|
||||
buffer[9] = (format->bitrate >> 11) & 0xFF;
|
||||
buffer[10] = (format->bitrate >> 19) & 0xFF;
|
||||
buffer[11] = (format->bitrate >> 27) & 0xFF;
|
||||
buffer[12] = (format->type->audio.block_align >> 0) & 0xFF;
|
||||
buffer[13] = (format->type->audio.block_align >> 8) & 0xFF;
|
||||
buffer[14] = (format->type->audio.bits_per_sample >> 0) & 0xFF;
|
||||
buffer[15] = (format->type->audio.bits_per_sample >> 8) & 0xFF;
|
||||
buffer[16] = (format->extradata_size >> 0) & 0xFF;
|
||||
buffer[17] = (format->extradata_size >> 8) & 0xFF;
|
||||
memcpy(buffer+18, format->extradata, format->extradata_size);
|
||||
return format->extradata_size + 18;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_CONTAINER_STATUS_T vc_container_waveformatex_to_es_format(uint8_t *p,
|
||||
unsigned int buffer_size, unsigned int *extra_offset, unsigned int *extra_size,
|
||||
VC_CONTAINER_ES_FORMAT_T *format)
|
||||
{
|
||||
VC_CONTAINER_FOURCC_T fourcc;
|
||||
uint32_t waveformat_id;
|
||||
|
||||
if(!p || buffer_size < 16) return VC_CONTAINER_ERROR_INVALID_ARGUMENT;
|
||||
waveformat_id = (p[1] << 8) | p[0];
|
||||
fourcc = waveformat_to_codec(waveformat_id);
|
||||
|
||||
/* Read the waveformatex header */
|
||||
if(extra_offset) *extra_offset = 16;
|
||||
if(extra_size) *extra_size = 0;
|
||||
format->type->audio.channels = p[2];
|
||||
format->type->audio.sample_rate = (p[7] << 24) | (p[6] << 16) | (p[5] << 8) | p[4];
|
||||
format->bitrate = ((p[11] << 24) | (p[10] << 16) | (p[9] << 8) | p[8]) * 8;
|
||||
format->type->audio.block_align = (p[13] << 8) | p[12];
|
||||
format->type->audio.bits_per_sample = (p[15] << 8) | p[14];
|
||||
|
||||
if(waveformat_id == WAVE_FORMAT_PCM && format->type->audio.bits_per_sample == 8)
|
||||
fourcc = VC_CONTAINER_CODEC_PCM_UNSIGNED_LE;
|
||||
|
||||
if(buffer_size >= 18)
|
||||
{
|
||||
if(extra_size)
|
||||
{
|
||||
*extra_size = (p[17] << 8) | p[16];
|
||||
if(*extra_size + 18 > buffer_size) *extra_size = buffer_size - 18;
|
||||
}
|
||||
if(extra_offset) *extra_offset = 18;
|
||||
}
|
||||
|
||||
/* Skip the MPEGLAYER3WAVEFORMAT structure */
|
||||
if(waveformat_id == WAVE_FORMAT_MPEGLAYER3 && extra_size)
|
||||
{
|
||||
if(extra_offset) *extra_offset += *extra_size;
|
||||
*extra_size = 0;
|
||||
}
|
||||
|
||||
format->es_type = VC_CONTAINER_ES_TYPE_AUDIO;
|
||||
format->codec = fourcc;
|
||||
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
unsigned int vc_container_es_format_to_bitmapinfoheader(VC_CONTAINER_ES_FORMAT_T *format,
|
||||
uint8_t *buffer, unsigned int buffer_size)
|
||||
{
|
||||
uint32_t fourcc = codec_to_vfw_fourcc(format->codec);
|
||||
uint32_t size = BITMAPINFOHEADER_SIZE_MAX + format->extradata_size;
|
||||
|
||||
if(format->es_type != VC_CONTAINER_ES_TYPE_VIDEO ||
|
||||
fourcc == VC_CONTAINER_CODEC_UNKNOWN) return 0;
|
||||
|
||||
if(!buffer) return size;
|
||||
if(buffer_size < size) return 0;
|
||||
|
||||
/* Build a bitmapinfoheader header */
|
||||
memset(buffer, 0, BITMAPINFOHEADER_SIZE_MAX);
|
||||
buffer[0] = (size >> 0) & 0xFF;
|
||||
buffer[1] = (size >> 8) & 0xFF;
|
||||
buffer[2] = (size >> 16) & 0xFF;
|
||||
buffer[3] = (size >> 24) & 0xFF;
|
||||
buffer[4] = (format->type->video.width >> 0) & 0xFF;
|
||||
buffer[5] = (format->type->video.width >> 8) & 0xFF;
|
||||
buffer[6] = (format->type->video.width >> 16) & 0xFF;
|
||||
buffer[7] = (format->type->video.width >> 24) & 0xFF;
|
||||
buffer[8] = (format->type->video.height >> 0) & 0xFF;
|
||||
buffer[9] = (format->type->video.height >> 8) & 0xFF;
|
||||
buffer[10] = (format->type->video.height >> 16) & 0xFF;
|
||||
buffer[11] = (format->type->video.height >> 24) & 0xFF;
|
||||
memcpy(buffer + 16, &fourcc, 4);
|
||||
memcpy(buffer + BITMAPINFOHEADER_SIZE_MAX, format->extradata, format->extradata_size);
|
||||
return size;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_CONTAINER_STATUS_T vc_container_bitmapinfoheader_to_es_format(uint8_t *p,
|
||||
unsigned int buffer_size, unsigned int *extra_offset, unsigned int *extra_size,
|
||||
VC_CONTAINER_ES_FORMAT_T *format)
|
||||
{
|
||||
VC_CONTAINER_FOURCC_T fourcc;
|
||||
|
||||
if(!p || buffer_size < BITMAPINFOHEADER_SIZE_MAX) return VC_CONTAINER_ERROR_INVALID_ARGUMENT;
|
||||
/* size = (p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]; */
|
||||
format->type->video.width = (p[7] << 24) | (p[6] << 16) | (p[5] << 8) | p[4];
|
||||
format->type->video.height = (p[11] << 24) | (p[10] << 16) | (p[9] << 8) | p[8];
|
||||
memcpy(&fourcc, p + 16, 4);
|
||||
|
||||
format->es_type = VC_CONTAINER_ES_TYPE_VIDEO;
|
||||
format->codec = vfw_fourcc_to_codec(fourcc);
|
||||
|
||||
/* If no mapping is found from vfw, try a more generic one */
|
||||
if (format->codec == fourcc && (fourcc = fourcc_to_codec(fourcc)) != VC_CONTAINER_CODEC_UNKNOWN)
|
||||
format->codec = fourcc;
|
||||
|
||||
if(extra_offset) *extra_offset = BITMAPINFOHEADER_SIZE_MAX;
|
||||
if(extra_size)
|
||||
{
|
||||
if (buffer_size > BITMAPINFOHEADER_SIZE_MAX)
|
||||
*extra_size = buffer_size - BITMAPINFOHEADER_SIZE_MAX;
|
||||
else
|
||||
*extra_size = 0;
|
||||
}
|
||||
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static struct {
|
||||
VC_CONTAINER_METADATA_KEY_T key;
|
||||
const char *name;
|
||||
} meta_key_conv[] =
|
||||
{ {VC_CONTAINER_METADATA_KEY_TITLE, "title"},
|
||||
{VC_CONTAINER_METADATA_KEY_ARTIST, "artist"},
|
||||
{VC_CONTAINER_METADATA_KEY_ALBUM, "album"},
|
||||
{VC_CONTAINER_METADATA_KEY_DESCRIPTION, "description"},
|
||||
{VC_CONTAINER_METADATA_KEY_YEAR, "year"},
|
||||
{VC_CONTAINER_METADATA_KEY_GENRE, "genre"},
|
||||
{VC_CONTAINER_METADATA_KEY_TRACK, "track"},
|
||||
{VC_CONTAINER_METADATA_KEY_LYRICS, "lyrics"},
|
||||
{VC_CONTAINER_METADATA_KEY_UNKNOWN, 0} };
|
||||
|
||||
/*****************************************************************************/
|
||||
const char *vc_container_metadata_id_to_string(VC_CONTAINER_METADATA_KEY_T key)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; meta_key_conv[i].key != VC_CONTAINER_METADATA_KEY_UNKNOWN; i++ )
|
||||
if(meta_key_conv[i].key == key) break;
|
||||
return meta_key_conv[i].name;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int64_t vc_container_maths_gcd(int64_t a, int64_t b)
|
||||
{
|
||||
while(b != 0)
|
||||
{
|
||||
int64_t t = b;
|
||||
b = a % b;
|
||||
a = t;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
void vc_container_maths_rational_simplify(uint32_t *num, uint32_t *den)
|
||||
{
|
||||
int64_t div = vc_container_maths_gcd((int64_t)*num, (int64_t)*den);
|
||||
if(div)
|
||||
{
|
||||
*num /= div;
|
||||
*den /= div;
|
||||
}
|
||||
}
|
86
gfx/include/userland/containers/core/containers_utils.h
Normal file
86
gfx/include/userland/containers/core/containers_utils.h
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef VC_CONTAINERS_UTILS_H
|
||||
#define VC_CONTAINERS_UTILS_H
|
||||
|
||||
#include "containers/containers.h"
|
||||
#include "containers/containers_codecs.h"
|
||||
#include "containers/core/containers_waveformat.h"
|
||||
|
||||
/*****************************************************************************
|
||||
* Type definitions
|
||||
*****************************************************************************/
|
||||
|
||||
/** Definition of the Global Unique Identifier type as used by some containers */
|
||||
typedef struct GUID_T
|
||||
{
|
||||
uint32_t word0;
|
||||
uint16_t short0;
|
||||
uint16_t short1;
|
||||
uint8_t bytes[8];
|
||||
|
||||
} GUID_T;
|
||||
|
||||
VC_CONTAINER_ES_FORMAT_T *vc_container_format_create(unsigned int extradata_size);
|
||||
void vc_container_format_delete(VC_CONTAINER_ES_FORMAT_T *);
|
||||
VC_CONTAINER_STATUS_T vc_container_format_extradata_alloc(
|
||||
VC_CONTAINER_ES_FORMAT_T *format, unsigned int size);
|
||||
VC_CONTAINER_STATUS_T vc_container_format_copy( VC_CONTAINER_ES_FORMAT_T *p_out,
|
||||
VC_CONTAINER_ES_FORMAT_T *p_in,
|
||||
unsigned int extra_buffer_size );
|
||||
int utf8_from_charset(const char *charset, char *out, unsigned int out_size,
|
||||
const void *in, unsigned int in_size);
|
||||
const char *vc_container_metadata_id_to_string(VC_CONTAINER_METADATA_KEY_T key);
|
||||
|
||||
unsigned int vc_container_es_format_to_waveformatex(VC_CONTAINER_ES_FORMAT_T *format,
|
||||
uint8_t *buffer, unsigned int buffer_size);
|
||||
unsigned int vc_container_es_format_to_bitmapinfoheader(VC_CONTAINER_ES_FORMAT_T *format,
|
||||
uint8_t *buffer, unsigned int buffer_size);
|
||||
VC_CONTAINER_STATUS_T vc_container_waveformatex_to_es_format(uint8_t *p,
|
||||
unsigned int buffer_size, unsigned int *extra_offset, unsigned int *extra_size,
|
||||
VC_CONTAINER_ES_FORMAT_T *format);
|
||||
VC_CONTAINER_STATUS_T vc_container_bitmapinfoheader_to_es_format(uint8_t *p,
|
||||
unsigned int buffer_size, unsigned int *extra_offset, unsigned int *extra_size,
|
||||
VC_CONTAINER_ES_FORMAT_T *format);
|
||||
|
||||
/** Find the greatest common denominator of 2 numbers.
|
||||
*
|
||||
* @param a first number
|
||||
* @param b second number
|
||||
*
|
||||
* @return greatest common denominator of a and b
|
||||
*/
|
||||
int64_t vc_container_maths_gcd(int64_t a, int64_t b);
|
||||
|
||||
/** Reduce a rational number to it's simplest form.
|
||||
*
|
||||
* @param num Pointer to the numerator of the rational number to simplify
|
||||
* @param den Pointer to the denominator of the rational number to simplify
|
||||
*/
|
||||
void vc_container_maths_rational_simplify(uint32_t *num, uint32_t *den);
|
||||
|
||||
#endif /* VC_CONTAINERS_UTILS_H */
|
180
gfx/include/userland/containers/core/containers_waveformat.h
Normal file
180
gfx/include/userland/containers/core/containers_waveformat.h
Normal file
@ -0,0 +1,180 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef VC_CONTAINERS_WAVEFORMAT_H
|
||||
#define VC_CONTAINERS_WAVEFORMAT_H
|
||||
|
||||
/* WAVE form wFormatTag IDs */
|
||||
#define WAVE_FORMAT_UNKNOWN 0x0000 /* Microsoft Corporation */
|
||||
#define WAVE_FORMAT_ADPCM 0x0002 /* Microsoft Corporation */
|
||||
#define WAVE_FORMAT_IEEE_FLOAT 0x0003 /* Microsoft Corporation */
|
||||
#define WAVE_FORMAT_VSELP 0x0004 /* Compaq Computer Corp. */
|
||||
#define WAVE_FORMAT_IBM_CVSD 0x0005 /* IBM Corporation */
|
||||
#define WAVE_FORMAT_ALAW 0x0006 /* Microsoft Corporation */
|
||||
#define WAVE_FORMAT_MULAW 0x0007 /* Microsoft Corporation */
|
||||
#define WAVE_FORMAT_DTS 0x0008 /* Microsoft Corporation */
|
||||
#define WAVE_FORMAT_DRM 0x0009 /* Microsoft Corporation */
|
||||
#define WAVE_FORMAT_WMAUDIO_VOICE 0x000A /* Microsoft Corporation */
|
||||
#define WAVE_FORMAT_OKI_ADPCM 0x0010 /* OKI */
|
||||
#define WAVE_FORMAT_DVI_ADPCM 0x0011 /* Intel Corporation */
|
||||
#define WAVE_FORMAT_IMA_ADPCM (WAVE_FORMAT_DVI_ADPCM) /* Intel Corporation */
|
||||
#define WAVE_FORMAT_MEDIASPACE_ADPCM 0x0012 /* Videologic */
|
||||
#define WAVE_FORMAT_SIERRA_ADPCM 0x0013 /* Sierra Semiconductor Corp */
|
||||
#define WAVE_FORMAT_G723_ADPCM 0x0014 /* Antex Electronics Corporation */
|
||||
#define WAVE_FORMAT_DIGISTD 0x0015 /* DSP Solutions, Inc. */
|
||||
#define WAVE_FORMAT_DIGIFIX 0x0016 /* DSP Solutions, Inc. */
|
||||
#define WAVE_FORMAT_DIALOGIC_OKI_ADPCM 0x0017 /* Dialogic Corporation */
|
||||
#define WAVE_FORMAT_MEDIAVISION_ADPCM 0x0018 /* Media Vision, Inc. */
|
||||
#define WAVE_FORMAT_CU_CODEC 0x0019 /* Hewlett-Packard Company */
|
||||
#define WAVE_FORMAT_YAMAHA_ADPCM 0x0020 /* Yamaha Corporation of America */
|
||||
#define WAVE_FORMAT_SONARC 0x0021 /* Speech Compression */
|
||||
#define WAVE_FORMAT_DSPGROUP_TRUESPEECH 0x0022 /* DSP Group, Inc */
|
||||
#define WAVE_FORMAT_ECHOSC1 0x0023 /* Echo Speech Corporation */
|
||||
#define WAVE_FORMAT_AUDIOFILE_AF36 0x0024 /* Virtual Music, Inc. */
|
||||
#define WAVE_FORMAT_APTX 0x0025 /* Audio Processing Technology */
|
||||
#define WAVE_FORMAT_AUDIOFILE_AF10 0x0026 /* Virtual Music, Inc. */
|
||||
#define WAVE_FORMAT_PROSODY_1612 0x0027 /* Aculab plc */
|
||||
#define WAVE_FORMAT_LRC 0x0028 /* Merging Technologies S.A. */
|
||||
#define WAVE_FORMAT_DOLBY_AC2 0x0030 /* Dolby Laboratories */
|
||||
#define WAVE_FORMAT_GSM610 0x0031 /* Microsoft Corporation */
|
||||
#define WAVE_FORMAT_MSNAUDIO 0x0032 /* Microsoft Corporation */
|
||||
#define WAVE_FORMAT_ANTEX_ADPCME 0x0033 /* Antex Electronics Corporation */
|
||||
#define WAVE_FORMAT_CONTROL_RES_VQLPC 0x0034 /* Control Resources Limited */
|
||||
#define WAVE_FORMAT_DIGIREAL 0x0035 /* DSP Solutions, Inc. */
|
||||
#define WAVE_FORMAT_DIGIADPCM 0x0036 /* DSP Solutions, Inc. */
|
||||
#define WAVE_FORMAT_CONTROL_RES_CR10 0x0037 /* Control Resources Limited */
|
||||
#define WAVE_FORMAT_NMS_VBXADPCM 0x0038 /* Natural MicroSystems */
|
||||
#define WAVE_FORMAT_CS_IMAADPCM 0x0039 /* Crystal Semiconductor IMA ADPCM */
|
||||
#define WAVE_FORMAT_ECHOSC3 0x003A /* Echo Speech Corporation */
|
||||
#define WAVE_FORMAT_ROCKWELL_ADPCM 0x003B /* Rockwell International */
|
||||
#define WAVE_FORMAT_ROCKWELL_DIGITALK 0x003C /* Rockwell International */
|
||||
#define WAVE_FORMAT_XEBEC 0x003D /* Xebec Multimedia Solutions Limited */
|
||||
#define WAVE_FORMAT_G721_ADPCM 0x0040 /* Antex Electronics Corporation */
|
||||
#define WAVE_FORMAT_G728_CELP 0x0041 /* Antex Electronics Corporation */
|
||||
#define WAVE_FORMAT_MSG723 0x0042 /* Microsoft Corporation */
|
||||
#define WAVE_FORMAT_PANASONIC_G726 0x0045 /* Not official Panasonic G.726 codec */
|
||||
#define WAVE_FORMAT_MPEG 0x0050 /* Microsoft Corporation */
|
||||
#define WAVE_FORMAT_RT24 0x0052 /* InSoft, Inc. */
|
||||
#define WAVE_FORMAT_PAC 0x0053 /* InSoft, Inc. */
|
||||
#define WAVE_FORMAT_MPEGLAYER3 0x0055 /* ISO/MPEG Layer3 Format Tag */
|
||||
#define WAVE_FORMAT_LUCENT_G723 0x0059 /* Lucent Technologies */
|
||||
#define WAVE_FORMAT_CIRRUS 0x0060 /* Cirrus Logic */
|
||||
#define WAVE_FORMAT_ESPCM 0x0061 /* ESS Technology */
|
||||
#define WAVE_FORMAT_VOXWARE 0x0062 /* Voxware Inc */
|
||||
#define WAVE_FORMAT_CANOPUS_ATRAC 0x0063 /* Canopus, co., Ltd. */
|
||||
#define WAVE_FORMAT_G726_ADPCM 0x0064 /* APICOM */
|
||||
#define WAVE_FORMAT_G722_ADPCM 0x0065 /* APICOM */
|
||||
#define WAVE_FORMAT_DSAT_DISPLAY 0x0067 /* Microsoft Corporation */
|
||||
#define WAVE_FORMAT_VOXWARE_BYTE_ALIGNED 0x0069 /* Voxware Inc */
|
||||
#define WAVE_FORMAT_VOXWARE_AC8 0x0070 /* Voxware Inc */
|
||||
#define WAVE_FORMAT_VOXWARE_AC10 0x0071 /* Voxware Inc */
|
||||
#define WAVE_FORMAT_VOXWARE_AC16 0x0072 /* Voxware Inc */
|
||||
#define WAVE_FORMAT_VOXWARE_AC20 0x0073 /* Voxware Inc */
|
||||
#define WAVE_FORMAT_VOXWARE_RT24 0x0074 /* Voxware Inc */
|
||||
#define WAVE_FORMAT_VOXWARE_RT29 0x0075 /* Voxware Inc */
|
||||
#define WAVE_FORMAT_VOXWARE_RT29HW 0x0076 /* Voxware Inc */
|
||||
#define WAVE_FORMAT_VOXWARE_VR12 0x0077 /* Voxware Inc */
|
||||
#define WAVE_FORMAT_VOXWARE_VR18 0x0078 /* Voxware Inc */
|
||||
#define WAVE_FORMAT_VOXWARE_TQ40 0x0079 /* Voxware Inc */
|
||||
#define WAVE_FORMAT_SOFTSOUND 0x0080 /* Softsound, Ltd. */
|
||||
#define WAVE_FORMAT_VOXWARE_TQ60 0x0081 /* Voxware Inc */
|
||||
#define WAVE_FORMAT_MSRT24 0x0082 /* Microsoft Corporation */
|
||||
#define WAVE_FORMAT_G729A 0x0083 /* AT&T Labs, Inc. */
|
||||
#define WAVE_FORMAT_MVI_MVI2 0x0084 /* Motion Pixels */
|
||||
#define WAVE_FORMAT_DF_G726 0x0085 /* DataFusion Systems (Pty) (Ltd) */
|
||||
#define WAVE_FORMAT_DF_GSM610 0x0086 /* DataFusion Systems (Pty) (Ltd) */
|
||||
#define WAVE_FORMAT_ISIAUDIO 0x0088 /* Iterated Systems, Inc. */
|
||||
#define WAVE_FORMAT_ONLIVE 0x0089 /* OnLive! Technologies, Inc. */
|
||||
#define WAVE_FORMAT_SBC24 0x0091 /* Siemens Business Communications Sys */
|
||||
#define WAVE_FORMAT_DOLBY_AC3_SPDIF 0x0092 /* Sonic Foundry */
|
||||
#define WAVE_FORMAT_MEDIASONIC_G723 0x0093 /* MediaSonic */
|
||||
#define WAVE_FORMAT_PROSODY_8KBPS 0x0094 /* Aculab plc */
|
||||
#define WAVE_FORMAT_ZYXEL_ADPCM 0x0097 /* ZyXEL Communications, Inc. */
|
||||
#define WAVE_FORMAT_PHILIPS_LPCBB 0x0098 /* Philips Speech Processing */
|
||||
#define WAVE_FORMAT_PACKED 0x0099 /* Studer Professional Audio AG */
|
||||
#define WAVE_FORMAT_MALDEN_PHONYTALK 0x00A0 /* Malden Electronics Ltd. */
|
||||
#define WAVE_FORMAT_MP4A 0x00FF /* AAC */
|
||||
#define WAVE_FORMAT_RHETOREX_ADPCM 0x0100 /* Rhetorex Inc. */
|
||||
#define WAVE_FORMAT_IRAT 0x0101 /* BeCubed Software Inc. */
|
||||
#define WAVE_FORMAT_VIVO_G723 0x0111 /* Vivo Software */
|
||||
#define WAVE_FORMAT_VIVO_SIREN 0x0112 /* Vivo Software */
|
||||
#define WAVE_FORMAT_DIGITAL_G723 0x0123 /* Digital Equipment Corporation */
|
||||
#define WAVE_FORMAT_SANYO_LD_ADPCM 0x0125 /* Sanyo Electric Co., Ltd. */
|
||||
#define WAVE_FORMAT_SIPROLAB_ACEPLNET 0x0130 /* Sipro Lab Telecom Inc. */
|
||||
#define WAVE_FORMAT_SIPROLAB_ACELP4800 0x0131 /* Sipro Lab Telecom Inc. */
|
||||
#define WAVE_FORMAT_SIPROLAB_ACELP8V3 0x0132 /* Sipro Lab Telecom Inc. */
|
||||
#define WAVE_FORMAT_SIPROLAB_G729 0x0133 /* Sipro Lab Telecom Inc. */
|
||||
#define WAVE_FORMAT_SIPROLAB_G729A 0x0134 /* Sipro Lab Telecom Inc. */
|
||||
#define WAVE_FORMAT_SIPROLAB_KELVIN 0x0135 /* Sipro Lab Telecom Inc. */
|
||||
#define WAVE_FORMAT_G726ADPCM 0x0140 /* Dictaphone Corporation */
|
||||
#define WAVE_FORMAT_QUALCOMM_PUREVOICE 0x0150 /* Qualcomm, Inc. */
|
||||
#define WAVE_FORMAT_QUALCOMM_HALFRATE 0x0151 /* Qualcomm, Inc. */
|
||||
#define WAVE_FORMAT_TUBGSM 0x0155 /* Ring Zero Systems, Inc. */
|
||||
#define WAVE_FORMAT_WMAUDIO1 0x0160 /* Microsoft Corporation */
|
||||
#define WAVE_FORMAT_WMAUDIO2 0x0161 /* Microsoft Corporation */
|
||||
#define WAVE_FORMAT_WMAUDIOPRO 0x0162 /* Microsoft Corporation */
|
||||
#define WAVE_FORMAT_WMAUDIO_LOSSLESS 0x0163 /* Microsoft Corporation */
|
||||
#define WAVE_FORMAT_UNISYS_NAP_ADPCM 0x0170 /* Unisys Corp. */
|
||||
#define WAVE_FORMAT_UNISYS_NAP_ULAW 0x0171 /* Unisys Corp. */
|
||||
#define WAVE_FORMAT_UNISYS_NAP_ALAW 0x0172 /* Unisys Corp. */
|
||||
#define WAVE_FORMAT_UNISYS_NAP_16K 0x0173 /* Unisys Corp. */
|
||||
#define WAVE_FORMAT_CREATIVE_ADPCM 0x0200 /* Creative Labs, Inc */
|
||||
#define WAVE_FORMAT_CREATIVE_FASTSPEECH8 0x0202 /* Creative Labs, Inc */
|
||||
#define WAVE_FORMAT_CREATIVE_FASTSPEECH10 0x0203 /* Creative Labs, Inc */
|
||||
#define WAVE_FORMAT_UHER_ADPCM 0x0210 /* UHER informatic GmbH */
|
||||
#define WAVE_FORMAT_QUARTERDECK 0x0220 /* Quarterdeck Corporation */
|
||||
#define WAVE_FORMAT_ILINK_VC 0x0230 /* I-link Worldwide */
|
||||
#define WAVE_FORMAT_RAW_SPORT 0x0240 /* Aureal Semiconductor */
|
||||
#define WAVE_FORMAT_ESST_AC3 0x0241 /* ESS Technology, Inc. */
|
||||
#define WAVE_FORMAT_IPI_HSX 0x0250 /* Interactive Products, Inc. */
|
||||
#define WAVE_FORMAT_IPI_RPELP 0x0251 /* Interactive Products, Inc. */
|
||||
#define WAVE_FORMAT_CS2 0x0260 /* Consistent Software */
|
||||
#define WAVE_FORMAT_SONY_SCX 0x0270 /* Sony Corp. */
|
||||
#define WAVE_FORMAT_FM_TOWNS_SND 0x0300 /* Fujitsu Corp. */
|
||||
#define WAVE_FORMAT_BTV_DIGITAL 0x0400 /* Brooktree Corporation */
|
||||
#define WAVE_FORMAT_QDESIGN_MUSIC 0x0450 /* QDesign Corporation */
|
||||
#define WAVE_FORMAT_VME_VMPCM 0x0680 /* AT&T Labs, Inc. */
|
||||
#define WAVE_FORMAT_TPC 0x0681 /* AT&T Labs, Inc. */
|
||||
#define WAVE_FORMAT_OLIGSM 0x1000 /* Ing C. Olivetti & C., S.p.A. */
|
||||
#define WAVE_FORMAT_OLIADPCM 0x1001 /* Ing C. Olivetti & C., S.p.A. */
|
||||
#define WAVE_FORMAT_OLICELP 0x1002 /* Ing C. Olivetti & C., S.p.A. */
|
||||
#define WAVE_FORMAT_OLISBC 0x1003 /* Ing C. Olivetti & C., S.p.A. */
|
||||
#define WAVE_FORMAT_OLIOPR 0x1004 /* Ing C. Olivetti & C., S.p.A. */
|
||||
#define WAVE_FORMAT_LH_CODEC 0x1100 /* Lernout & Hauspie */
|
||||
#define WAVE_FORMAT_NORRIS 0x1400 /* Norris Communications, Inc. */
|
||||
#define WAVE_FORMAT_SOUNDSPACE_MUSICOMPRESS 0x1500 /* AT&T Labs, Inc. */
|
||||
#define WAVE_FORMAT_DVM 0x2000 /* FAST Multimedia AG */
|
||||
#define WAVE_FORMAT_AAC 0x706D /* AAC */
|
||||
|
||||
#if !defined(WAVE_FORMAT_EXTENSIBLE)
|
||||
#define WAVE_FORMAT_EXTENSIBLE 0xFFFE /* Microsoft */
|
||||
#endif // !defined(WAVE_FORMAT_EXTENSIBLE)
|
||||
|
||||
#if !defined(WAVE_FORMAT_PCM)
|
||||
#define WAVE_FORMAT_PCM 0x0001
|
||||
#endif // !defined(WAVE_FORMAT_PCM)
|
||||
|
||||
#endif /* VC_CONTAINERS_WAVEFORMAT_H */
|
127
gfx/include/userland/containers/core/containers_writer_utils.c
Normal file
127
gfx/include/userland/containers/core/containers_writer_utils.c
Normal file
@ -0,0 +1,127 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "containers/containers.h"
|
||||
#include "containers/core/containers_private.h"
|
||||
#include "containers/core/containers_utils.h"
|
||||
#include "containers/core/containers_writer_utils.h"
|
||||
#include "vcos.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T vc_container_writer_extraio_create(VC_CONTAINER_T *context, const char *uri,
|
||||
VC_CONTAINER_WRITER_EXTRAIO_T *extraio)
|
||||
{
|
||||
VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
|
||||
VC_CONTAINER_PARAM_UNUSED(context);
|
||||
|
||||
extraio->io = vc_container_io_open( uri, VC_CONTAINER_IO_MODE_WRITE, &status );
|
||||
extraio->refcount = 0;
|
||||
extraio->temp = 0;
|
||||
return status;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_CONTAINER_STATUS_T vc_container_writer_extraio_create_null(VC_CONTAINER_T *context, VC_CONTAINER_WRITER_EXTRAIO_T *extraio)
|
||||
{
|
||||
return vc_container_writer_extraio_create(context, "null://", extraio);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_CONTAINER_STATUS_T vc_container_writer_extraio_create_temp(VC_CONTAINER_T *context, VC_CONTAINER_WRITER_EXTRAIO_T *extraio)
|
||||
{
|
||||
VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
|
||||
unsigned int length = strlen(context->priv->io->uri) + 5;
|
||||
char *uri = malloc(length);
|
||||
if(!uri) return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
snprintf(uri, length, "%s.tmp", context->priv->io->uri);
|
||||
status = vc_container_writer_extraio_create(context, uri, extraio);
|
||||
free(uri);
|
||||
extraio->temp = true;
|
||||
|
||||
if(status == VC_CONTAINER_SUCCESS && !context->priv->tmp_io)
|
||||
context->priv->tmp_io = extraio->io;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_CONTAINER_STATUS_T vc_container_writer_extraio_delete(VC_CONTAINER_T *context, VC_CONTAINER_WRITER_EXTRAIO_T *extraio)
|
||||
{
|
||||
VC_CONTAINER_STATUS_T status;
|
||||
char *uri = extraio->temp ? vcos_strdup(extraio->io->uri) : 0;
|
||||
|
||||
while(extraio->refcount) vc_container_writer_extraio_disable(context, extraio);
|
||||
status = vc_container_io_close( extraio->io );
|
||||
|
||||
/* coverity[check_return] On failure the worst case is a file or directory is not removed */
|
||||
if(uri) remove(uri);
|
||||
if(uri) free(uri);
|
||||
|
||||
if(context->priv->tmp_io == extraio->io)
|
||||
context->priv->tmp_io = 0;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int64_t vc_container_writer_extraio_enable(VC_CONTAINER_T *context, VC_CONTAINER_WRITER_EXTRAIO_T *extraio)
|
||||
{
|
||||
VC_CONTAINER_IO_T *tmp;
|
||||
|
||||
if(!extraio->refcount)
|
||||
{
|
||||
vc_container_io_seek(extraio->io, INT64_C(0));
|
||||
tmp = context->priv->io;
|
||||
context->priv->io = extraio->io;
|
||||
extraio->io = tmp;
|
||||
}
|
||||
return extraio->refcount++;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int64_t vc_container_writer_extraio_disable(VC_CONTAINER_T *context, VC_CONTAINER_WRITER_EXTRAIO_T *extraio)
|
||||
{
|
||||
VC_CONTAINER_IO_T *tmp;
|
||||
|
||||
if(extraio->refcount)
|
||||
{
|
||||
extraio->refcount--;
|
||||
if(!extraio->refcount)
|
||||
{
|
||||
tmp = context->priv->io;
|
||||
context->priv->io = extraio->io;
|
||||
extraio->io = tmp;
|
||||
}
|
||||
}
|
||||
return extraio->refcount;
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef VC_CONTAINERS_WRITER_UTILS_H
|
||||
#define VC_CONTAINERS_WRITER_UTILS_H
|
||||
|
||||
/** \file containers_writer_utils.h
|
||||
* Helper functions and macros for container writers
|
||||
*/
|
||||
|
||||
#include "containers/containers.h"
|
||||
#include "containers/containers_codecs.h"
|
||||
#include "containers/core/containers_io_helpers.h"
|
||||
|
||||
/*****************************************************************************
|
||||
* Helper inline functions to write format specific structus to an i/o stream
|
||||
*****************************************************************************/
|
||||
|
||||
STATIC_INLINE VC_CONTAINER_STATUS_T vc_container_write_waveformatex( VC_CONTAINER_T *p_ctx,
|
||||
VC_CONTAINER_ES_FORMAT_T *format)
|
||||
{
|
||||
/* Write waveformatex structure */
|
||||
WRITE_U16(p_ctx, codec_to_waveformat(format->codec), "Codec ID");
|
||||
WRITE_U16(p_ctx, format->type->audio.channels, "Number of Channels");
|
||||
WRITE_U32(p_ctx, format->type->audio.sample_rate, "Samples per Second");
|
||||
WRITE_U32(p_ctx, format->bitrate >> 3, "Average Number of Bytes Per Second");
|
||||
WRITE_U16(p_ctx, format->type->audio.block_align, "Block Alignment");
|
||||
WRITE_U16(p_ctx, format->type->audio.bits_per_sample, "Bits Per Sample");
|
||||
WRITE_U16(p_ctx, format->extradata_size, "Codec Specific Data Size");
|
||||
WRITE_BYTES(p_ctx, format->extradata, format->extradata_size);
|
||||
|
||||
return STREAM_STATUS(p_ctx);
|
||||
}
|
||||
|
||||
STATIC_INLINE VC_CONTAINER_STATUS_T vc_container_write_bitmapinfoheader( VC_CONTAINER_T *p_ctx,
|
||||
VC_CONTAINER_ES_FORMAT_T *format)
|
||||
{
|
||||
VC_CONTAINER_FOURCC_T fourcc;
|
||||
|
||||
/* Write bitmapinfoheader structure */
|
||||
WRITE_U32(p_ctx, 40, "Format Data Size");
|
||||
WRITE_U32(p_ctx, format->type->video.width, "Image Width");
|
||||
WRITE_U32(p_ctx, format->type->video.height, "Image Height");
|
||||
WRITE_U16(p_ctx, 0, "Reserved");
|
||||
WRITE_U16(p_ctx, 0, "Bits Per Pixel Count");
|
||||
fourcc = codec_to_vfw_fourcc(format->codec);
|
||||
WRITE_BYTES(p_ctx, (char *)&fourcc, 4); /* Compression ID */
|
||||
LOG_FORMAT(p_ctx, "Compression ID: %4.4s", (char *)&fourcc);
|
||||
WRITE_U32(p_ctx, 0, "Image Size");
|
||||
WRITE_U32(p_ctx, 0, "Horizontal Pixels Per Meter");
|
||||
WRITE_U32(p_ctx, 0, "Vertical Pixels Per Meter");
|
||||
WRITE_U32(p_ctx, 0, "Colors Used Count");
|
||||
WRITE_U32(p_ctx, 0, "Important Colors Count");
|
||||
|
||||
WRITE_BYTES(p_ctx, format->extradata, format->extradata_size);
|
||||
|
||||
return STREAM_STATUS(p_ctx);
|
||||
}
|
||||
|
||||
/* Helper functions to create and use extra i/o */
|
||||
typedef struct VC_CONTAINER_WRITER_EXTRAIO_T {
|
||||
VC_CONTAINER_IO_T *io;
|
||||
unsigned int refcount;
|
||||
bool temp;
|
||||
} VC_CONTAINER_WRITER_EXTRAIO_T;
|
||||
|
||||
VC_CONTAINER_STATUS_T vc_container_writer_extraio_create_null(VC_CONTAINER_T *context, VC_CONTAINER_WRITER_EXTRAIO_T *null);
|
||||
VC_CONTAINER_STATUS_T vc_container_writer_extraio_create_temp(VC_CONTAINER_T *context, VC_CONTAINER_WRITER_EXTRAIO_T *null);
|
||||
VC_CONTAINER_STATUS_T vc_container_writer_extraio_delete(VC_CONTAINER_T *context, VC_CONTAINER_WRITER_EXTRAIO_T *null);
|
||||
int64_t vc_container_writer_extraio_enable(VC_CONTAINER_T *context, VC_CONTAINER_WRITER_EXTRAIO_T *null);
|
||||
int64_t vc_container_writer_extraio_disable(VC_CONTAINER_T *context, VC_CONTAINER_WRITER_EXTRAIO_T *null);
|
||||
|
||||
#endif /* VC_CONTAINERS_WRITER_UTILS_H */
|
233
gfx/include/userland/containers/core/packetizers.c
Normal file
233
gfx/include/userland/containers/core/packetizers.c
Normal file
@ -0,0 +1,233 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "containers/packetizers.h"
|
||||
#include "containers/core/packetizers_private.h"
|
||||
#include "containers/core/containers_common.h"
|
||||
#include "containers/core/containers_logging.h"
|
||||
#include "containers/core/containers_utils.h"
|
||||
|
||||
/** List of registered packetizers. */
|
||||
static VC_PACKETIZER_REGISTRY_ENTRY_T *registry;
|
||||
|
||||
/*****************************************************************************/
|
||||
void vc_packetizer_register(VC_PACKETIZER_REGISTRY_ENTRY_T *entry)
|
||||
{
|
||||
LOG_DEBUG(0, "registering packetizer %s", entry->name);
|
||||
entry->next = registry;
|
||||
registry = entry;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T vc_packetizer_load(VC_PACKETIZER_T *p_ctx)
|
||||
{
|
||||
VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
VC_PACKETIZER_REGISTRY_ENTRY_T *entry;
|
||||
|
||||
/* Try all the packetizers until we find the right one */
|
||||
for (entry = registry; entry; entry = entry->next)
|
||||
{
|
||||
status = entry->open(p_ctx);
|
||||
if(status != VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED)
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static void vc_packetizer_unload(VC_PACKETIZER_T *p_ctx)
|
||||
{
|
||||
VC_CONTAINER_PARAM_UNUSED(p_ctx);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_PACKETIZER_T *vc_packetizer_open( VC_CONTAINER_ES_FORMAT_T *in,
|
||||
VC_CONTAINER_FOURCC_T out_variant, VC_CONTAINER_STATUS_T *p_status )
|
||||
{
|
||||
VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
|
||||
VC_PACKETIZER_T *p_ctx = 0;
|
||||
|
||||
/* Allocate our context before trying out the different packetizers */
|
||||
p_ctx = malloc( sizeof(*p_ctx) + sizeof(*p_ctx->priv));
|
||||
if(!p_ctx) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
|
||||
memset(p_ctx, 0, sizeof(*p_ctx) + sizeof(*p_ctx->priv));
|
||||
p_ctx->priv = (VC_PACKETIZER_PRIVATE_T *)(p_ctx + 1);
|
||||
bytestream_init( &p_ctx->priv->stream );
|
||||
|
||||
p_ctx->in = vc_container_format_create(in->extradata_size);
|
||||
if(!p_ctx->in) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
|
||||
p_ctx->out = vc_container_format_create(in->extradata_size);
|
||||
if(!p_ctx->out) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
|
||||
|
||||
vc_container_format_copy( p_ctx->in, in, in->extradata_size );
|
||||
p_ctx->in->extradata_size = 0;
|
||||
vc_container_format_copy( p_ctx->out, p_ctx->in, in->extradata_size );
|
||||
p_ctx->in->extradata_size = in->extradata_size;
|
||||
p_ctx->out->extradata = p_ctx->in->extradata;
|
||||
p_ctx->out->extradata_size = p_ctx->in->extradata_size;
|
||||
p_ctx->out->codec_variant = out_variant;
|
||||
|
||||
vc_container_time_init(&p_ctx->priv->time, 1000000);
|
||||
|
||||
status = vc_packetizer_load(p_ctx);
|
||||
if(status != VC_CONTAINER_SUCCESS)
|
||||
goto error;
|
||||
|
||||
end:
|
||||
if(p_status) *p_status = status;
|
||||
return p_ctx;
|
||||
|
||||
error:
|
||||
if(p_ctx) vc_packetizer_close(p_ctx);
|
||||
p_ctx = NULL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_CONTAINER_STATUS_T vc_packetizer_close( VC_PACKETIZER_T *p_ctx )
|
||||
{
|
||||
VC_CONTAINER_BYTESTREAM_T *stream;
|
||||
VC_CONTAINER_PACKET_T *packet, *next;
|
||||
|
||||
if(!p_ctx) return VC_CONTAINER_SUCCESS;
|
||||
|
||||
stream = &p_ctx->priv->stream;
|
||||
|
||||
if(p_ctx->in) vc_container_format_delete(p_ctx->in);
|
||||
if(p_ctx->out) vc_container_format_delete(p_ctx->out);
|
||||
if(p_ctx->priv->pf_close) p_ctx->priv->pf_close(p_ctx);
|
||||
if(p_ctx->priv->module_handle) vc_packetizer_unload(p_ctx);
|
||||
|
||||
/* Free the bytestream */
|
||||
for(packet = stream->first; packet; packet = next)
|
||||
{
|
||||
next = packet->next;
|
||||
if(packet->framework_data) free(packet);
|
||||
}
|
||||
|
||||
free(p_ctx);
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_CONTAINER_STATUS_T vc_packetizer_push( VC_PACKETIZER_T *p_ctx,
|
||||
VC_CONTAINER_PACKET_T *in)
|
||||
{
|
||||
/* Do some sanity checking on packet ? */
|
||||
|
||||
in->framework_data = 0;
|
||||
bytestream_push(&p_ctx->priv->stream, in);
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_CONTAINER_STATUS_T vc_packetizer_pop( VC_PACKETIZER_T *p_ctx,
|
||||
VC_CONTAINER_PACKET_T **in, VC_PACKETIZER_FLAGS_T flags)
|
||||
{
|
||||
VC_CONTAINER_BYTESTREAM_T *stream = &p_ctx->priv->stream;
|
||||
VC_CONTAINER_PACKET_T *packet, *new, **prev;
|
||||
|
||||
/* Release the packets which have been read */
|
||||
while((*in = bytestream_pop(stream)) != NULL)
|
||||
{
|
||||
if(*in && (*in)->framework_data)
|
||||
{
|
||||
free(*in);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(*in)
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
if(!(flags & VC_PACKETIZER_FLAG_FORCE_RELEASE_INPUT))
|
||||
return VC_CONTAINER_ERROR_INCOMPLETE_DATA;
|
||||
|
||||
/* Look for the 1st non-framework packet */
|
||||
for (packet = stream->first, prev = &stream->first;
|
||||
packet && packet->framework_data; prev = &packet->next, packet = packet->next);
|
||||
|
||||
if (!packet || (packet && packet->framework_data))
|
||||
return VC_CONTAINER_ERROR_INCOMPLETE_DATA;
|
||||
|
||||
/* We'll currently alloc an internal packet for each packet the client forcefully releases.
|
||||
* We could probably do something a bit more clever than that though. */
|
||||
/* Replace the packet with a newly allocated one */
|
||||
new = malloc(sizeof(*packet) + packet->size);
|
||||
if(!new)
|
||||
return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
*new = *packet;
|
||||
new->framework_data = new;
|
||||
if(!new->next)
|
||||
stream->last = &new->next;
|
||||
if(stream->current == packet)
|
||||
stream->current = new;
|
||||
*prev = new;
|
||||
new->data = (uint8_t *)&new[1];
|
||||
memcpy(new->data, packet->data, packet->size);
|
||||
*in = packet;
|
||||
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_CONTAINER_STATUS_T vc_packetizer_read( VC_PACKETIZER_T *p_ctx,
|
||||
VC_CONTAINER_PACKET_T *packet, VC_PACKETIZER_FLAGS_T flags)
|
||||
{
|
||||
if(!packet && !(flags & VC_CONTAINER_READ_FLAG_SKIP))
|
||||
return VC_CONTAINER_ERROR_INVALID_ARGUMENT;
|
||||
if(!packet && (flags & VC_CONTAINER_READ_FLAG_INFO))
|
||||
return VC_CONTAINER_ERROR_INVALID_ARGUMENT;
|
||||
if(packet && !packet->data &&
|
||||
(!(flags & VC_CONTAINER_READ_FLAG_INFO) &&
|
||||
!(flags & VC_CONTAINER_READ_FLAG_SKIP)))
|
||||
return VC_CONTAINER_ERROR_INVALID_ARGUMENT;
|
||||
|
||||
/* Always having a packet structure to work with simplifies things */
|
||||
if(!packet)
|
||||
packet = &p_ctx->priv->packet;
|
||||
|
||||
return p_ctx->priv->pf_packetize(p_ctx, packet, flags);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_CONTAINER_STATUS_T vc_packetizer_reset( VC_PACKETIZER_T *p_ctx )
|
||||
{
|
||||
VC_CONTAINER_BYTESTREAM_T *stream = &p_ctx->priv->stream;
|
||||
|
||||
bytestream_skip( stream, stream->bytes - stream->current_offset - stream->offset );
|
||||
|
||||
if (p_ctx->priv->pf_reset)
|
||||
return p_ctx->priv->pf_reset(p_ctx);
|
||||
else
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
111
gfx/include/userland/containers/core/packetizers_private.h
Normal file
111
gfx/include/userland/containers/core/packetizers_private.h
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef VC_PACKETIZERS_PRIVATE_H
|
||||
#define VC_PACKETIZERS_PRIVATE_H
|
||||
|
||||
/** \file
|
||||
* Private interface for packetizers
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include "containers/packetizers.h"
|
||||
#include "containers/core/containers_common.h"
|
||||
#include "containers/core/containers_bytestream.h"
|
||||
#include "containers/core/containers_time.h"
|
||||
|
||||
/** \defgroup VcPacketizerModuleApi Packetizer Module API
|
||||
* Private interface for modules implementing packetizers */
|
||||
/* @{ */
|
||||
|
||||
/** Context private to the packetizer instance. This private context is used to
|
||||
* store data which shouldn't be exported by the public API. */
|
||||
typedef struct VC_PACKETIZER_PRIVATE_T
|
||||
{
|
||||
/** Pointer to the private data of the packetizer module in use */
|
||||
struct VC_PACKETIZER_MODULE_T *module;
|
||||
|
||||
/** Bytestream abstraction layer */
|
||||
struct VC_CONTAINER_BYTESTREAM_T stream;
|
||||
|
||||
/** Current stream time */
|
||||
VC_CONTAINER_TIME_T time;
|
||||
|
||||
/** Packetize the bytestream.
|
||||
*
|
||||
* \param context Pointer to the context of the instance of the packetizer
|
||||
* \param out Pointer to the output packet structure which needs to be filled
|
||||
* \param flags Miscellaneous flags controlling the packetizing
|
||||
* \return the status of the operation
|
||||
*/
|
||||
VC_CONTAINER_STATUS_T (*pf_packetize)( VC_PACKETIZER_T *context,
|
||||
VC_CONTAINER_PACKET_T *out, VC_PACKETIZER_FLAGS_T flags );
|
||||
|
||||
/** Reset packetizer state.
|
||||
*
|
||||
* \param context Pointer to the context of the instance of the packetizer
|
||||
* \return the status of the operation
|
||||
*/
|
||||
VC_CONTAINER_STATUS_T (*pf_reset)( VC_PACKETIZER_T *context );
|
||||
|
||||
/** Closes a packetizer module.
|
||||
*
|
||||
* \param context Pointer to the context of the instance to close
|
||||
* \return the status of the operation
|
||||
*/
|
||||
VC_CONTAINER_STATUS_T (*pf_close)( struct VC_PACKETIZER_T *context );
|
||||
|
||||
/** Pointer to the packetizer module code and symbols*/
|
||||
void *module_handle;
|
||||
|
||||
/** Temporary packet structure used when the caller does not provide one */
|
||||
VC_CONTAINER_PACKET_T packet;
|
||||
|
||||
} VC_PACKETIZER_PRIVATE_T;
|
||||
|
||||
/** Structure used by packetizers to register themselves with the core. */
|
||||
typedef struct VC_PACKETIZER_REGISTRY_ENTRY_T
|
||||
{
|
||||
struct VC_PACKETIZER_REGISTRY_ENTRY_T *next; /**< To link entries together */
|
||||
const char *name; /**< Name of the packetizer */
|
||||
VC_CONTAINER_STATUS_T (*open)( VC_PACKETIZER_T * ); /**< Called to open packetizer */
|
||||
} VC_PACKETIZER_REGISTRY_ENTRY_T;
|
||||
|
||||
/** Register a packetizer with the core.
|
||||
*
|
||||
* \param entry Entry to register with the core
|
||||
*/
|
||||
void vc_packetizer_register(VC_PACKETIZER_REGISTRY_ENTRY_T *entry);
|
||||
|
||||
/** Utility macro used to register a packetizer with the core */
|
||||
#define VC_PACKETIZER_REGISTER(func, name) \
|
||||
VC_CONTAINER_CONSTRUCTOR(func##_register); \
|
||||
static VC_PACKETIZER_REGISTRY_ENTRY_T registry_entry = {0, name, func}; \
|
||||
void func##_register(void) { vc_packetizer_register(®istry_entry); }
|
||||
|
||||
/* @} */
|
||||
|
||||
#endif /* VC_PACKETIZERS_PRIVATE_H */
|
12
gfx/include/userland/containers/dummy/CMakeLists.txt
Normal file
12
gfx/include/userland/containers/dummy/CMakeLists.txt
Normal file
@ -0,0 +1,12 @@
|
||||
# Container module needs to go in as a plugins so different prefix
|
||||
# and install path
|
||||
set(CMAKE_SHARED_LIBRARY_PREFIX "")
|
||||
|
||||
# Make sure the compiler can find the necessary include files
|
||||
include_directories (../..)
|
||||
|
||||
add_library(writer_dummy ${LIBRARY_TYPE} dummy_writer.c)
|
||||
|
||||
target_link_libraries(writer_dummy containers)
|
||||
|
||||
install(TARGETS writer_dummy DESTINATION ${VMCS_PLUGIN_DIR})
|
137
gfx/include/userland/containers/dummy/dummy_writer.c
Normal file
137
gfx/include/userland/containers/dummy/dummy_writer.c
Normal file
@ -0,0 +1,137 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "containers/core/containers_private.h"
|
||||
#include "containers/core/containers_io_helpers.h"
|
||||
#include "containers/core/containers_utils.h"
|
||||
#include "containers/core/containers_logging.h"
|
||||
|
||||
/******************************************************************************
|
||||
Type definitions
|
||||
******************************************************************************/
|
||||
typedef struct VC_CONTAINER_MODULE_T
|
||||
{
|
||||
VC_CONTAINER_TRACK_T *track[2];
|
||||
|
||||
} VC_CONTAINER_MODULE_T;
|
||||
|
||||
/******************************************************************************
|
||||
Function prototypes
|
||||
******************************************************************************/
|
||||
VC_CONTAINER_STATUS_T dummy_writer_open( VC_CONTAINER_T * );
|
||||
|
||||
/*****************************************************************************
|
||||
Functions exported as part of the Container Module API
|
||||
*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T dummy_writer_close( VC_CONTAINER_T *p_ctx )
|
||||
{
|
||||
VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
|
||||
for(; p_ctx->tracks_num > 0; p_ctx->tracks_num--)
|
||||
vc_container_free_track(p_ctx, p_ctx->tracks[p_ctx->tracks_num-1]);
|
||||
free(module);
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T dummy_writer_write( VC_CONTAINER_T *p_ctx,
|
||||
VC_CONTAINER_PACKET_T *packet )
|
||||
{
|
||||
VC_CONTAINER_PARAM_UNUSED(p_ctx);
|
||||
VC_CONTAINER_PARAM_UNUSED(packet);
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T dummy_writer_control( VC_CONTAINER_T *p_ctx,
|
||||
VC_CONTAINER_CONTROL_T operation, va_list args )
|
||||
{
|
||||
VC_CONTAINER_TRACK_T *track;
|
||||
VC_CONTAINER_PARAM_UNUSED(args);
|
||||
|
||||
switch(operation)
|
||||
{
|
||||
case VC_CONTAINER_CONTROL_TRACK_ADD:
|
||||
if(p_ctx->tracks_num >= 2) return VC_CONTAINER_ERROR_OUT_OF_RESOURCES;
|
||||
|
||||
/* Allocate and initialise track data */
|
||||
p_ctx->tracks[p_ctx->tracks_num] = track = vc_container_allocate_track(p_ctx, 0);
|
||||
if(!track) return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
p_ctx->tracks_num++;
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
|
||||
case VC_CONTAINER_CONTROL_TRACK_ADD_DONE:
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
|
||||
default: return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_CONTAINER_STATUS_T dummy_writer_open( VC_CONTAINER_T *p_ctx )
|
||||
{
|
||||
const char *extension = vc_uri_path_extension(p_ctx->priv->uri);
|
||||
VC_CONTAINER_MODULE_T *module = 0;
|
||||
VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_FORMAT_INVALID;
|
||||
|
||||
/* Check if the user has specified a container */
|
||||
vc_uri_find_query(p_ctx->priv->uri, 0, "container", &extension);
|
||||
|
||||
/* Check we're the right writer for this */
|
||||
if(!extension)
|
||||
return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
if(strcasecmp(extension, "dummy"))
|
||||
return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
|
||||
/* Allocate our context */
|
||||
module = malloc(sizeof(*module));
|
||||
if(!module) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
|
||||
memset(module, 0, sizeof(*module));
|
||||
p_ctx->priv->module = module;
|
||||
p_ctx->tracks = module->track;
|
||||
|
||||
p_ctx->capabilities |= VC_CONTAINER_CAPS_DYNAMIC_TRACK_ADD;
|
||||
|
||||
p_ctx->priv->pf_close = dummy_writer_close;
|
||||
p_ctx->priv->pf_write = dummy_writer_write;
|
||||
p_ctx->priv->pf_control = dummy_writer_control;
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
|
||||
error:
|
||||
LOG_DEBUG(p_ctx, "dummy: error opening stream (%i)", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
/********************************************************************************
|
||||
Entrypoint function
|
||||
********************************************************************************/
|
||||
|
||||
#if !defined(ENABLE_CONTAINERS_STANDALONE) && defined(__HIGHC__)
|
||||
# pragma weak writer_open dummy_writer_open
|
||||
#endif
|
13
gfx/include/userland/containers/flash/CMakeLists.txt
Normal file
13
gfx/include/userland/containers/flash/CMakeLists.txt
Normal file
@ -0,0 +1,13 @@
|
||||
# Container module needs to go in as a plugins so different prefix
|
||||
# and install path
|
||||
set(CMAKE_SHARED_LIBRARY_PREFIX "")
|
||||
|
||||
# Make sure the compiler can find the necessary include files
|
||||
include_directories (../..)
|
||||
|
||||
add_library(reader_flv ${LIBRARY_TYPE} flv_reader.c)
|
||||
|
||||
target_link_libraries(reader_flv containers)
|
||||
|
||||
install(TARGETS reader_flv DESTINATION ${VMCS_PLUGIN_DIR})
|
||||
|
1174
gfx/include/userland/containers/flash/flv_reader.c
Normal file
1174
gfx/include/userland/containers/flash/flv_reader.c
Normal file
File diff suppressed because it is too large
Load Diff
343
gfx/include/userland/containers/h264/avc1_packetizer.c
Normal file
343
gfx/include/userland/containers/h264/avc1_packetizer.c
Normal file
@ -0,0 +1,343 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* Implementation of an ISO 14496-15 to Annexe-B AVC video packetizer.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "containers/packetizers.h"
|
||||
#include "containers/core/packetizers_private.h"
|
||||
#include "containers/core/containers_common.h"
|
||||
#include "containers/core/containers_logging.h"
|
||||
#include "containers/core/containers_utils.h"
|
||||
#include "containers/core/containers_bytestream.h"
|
||||
|
||||
#ifndef ENABLE_CONTAINERS_LOG_FORMAT_VERBOSE
|
||||
//#define ENABLE_CONTAINERS_LOG_FORMAT_VERBOSE
|
||||
#endif
|
||||
|
||||
/** Arbitrary number which should be sufficiently high so that no sane frame will
|
||||
* be bigger than that. */
|
||||
#define MAX_FRAME_SIZE (1920*1088*2)
|
||||
|
||||
VC_CONTAINER_STATUS_T avc1_packetizer_open( VC_PACKETIZER_T * );
|
||||
|
||||
/*****************************************************************************/
|
||||
typedef struct VC_PACKETIZER_MODULE_T {
|
||||
enum {
|
||||
STATE_FRAME_WAIT = 0,
|
||||
STATE_BUFFER_INIT,
|
||||
STATE_NAL_START,
|
||||
STATE_NAL_DATA,
|
||||
} state;
|
||||
|
||||
unsigned int length_size;
|
||||
|
||||
unsigned int frame_size;
|
||||
unsigned int bytes_read;
|
||||
unsigned int start_code_bytes_left;
|
||||
unsigned int nal_bytes_left;
|
||||
|
||||
} VC_PACKETIZER_MODULE_T;
|
||||
|
||||
static const uint8_t h264_start_code[] = {0, 0, 0, 1};
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T avc1_packetizer_close( VC_PACKETIZER_T *p_ctx )
|
||||
{
|
||||
free(p_ctx->priv->module);
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T avc1_packetizer_reset( VC_PACKETIZER_T *p_ctx )
|
||||
{
|
||||
VC_PACKETIZER_MODULE_T *module = p_ctx->priv->module;
|
||||
module->state = STATE_FRAME_WAIT;
|
||||
module->frame_size = 0;
|
||||
module->bytes_read = 0;
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T avc1_packetizer_packetize( VC_PACKETIZER_T *p_ctx,
|
||||
VC_CONTAINER_PACKET_T *out, VC_PACKETIZER_FLAGS_T flags)
|
||||
{
|
||||
VC_PACKETIZER_MODULE_T *module = p_ctx->priv->module;
|
||||
VC_CONTAINER_BYTESTREAM_T *stream = &p_ctx->priv->stream;
|
||||
VC_CONTAINER_PACKET_T *packet;
|
||||
unsigned int offset, size, nal_num;
|
||||
uint8_t data[4];
|
||||
VC_CONTAINER_PARAM_UNUSED(nal_num);
|
||||
|
||||
while(1) switch (module->state)
|
||||
{
|
||||
case STATE_FRAME_WAIT:
|
||||
for (packet = stream->current, size = 0;
|
||||
packet && !(packet->flags & VC_CONTAINER_PACKET_FLAG_FRAME_END);
|
||||
packet = packet->next)
|
||||
size += packet->size;
|
||||
if (!packet)
|
||||
return VC_CONTAINER_ERROR_INCOMPLETE_DATA; /* We need more data */
|
||||
|
||||
size += packet->size;
|
||||
|
||||
/* We now have a complete frame available */
|
||||
|
||||
module->nal_bytes_left = 0;
|
||||
module->start_code_bytes_left = 0;
|
||||
|
||||
/* Find out the number of NAL units and size of the frame */
|
||||
for (offset = nal_num = 0; offset + module->length_size < size; nal_num++)
|
||||
{
|
||||
unsigned int nal_size;
|
||||
|
||||
bytestream_peek_at(stream, offset, data, module->length_size);
|
||||
offset += module->length_size;
|
||||
|
||||
nal_size = data[0];
|
||||
if (module->length_size > 1)
|
||||
nal_size = (nal_size << 8)|data[1];
|
||||
if (module->length_size > 2)
|
||||
nal_size = (nal_size << 8)|data[2];
|
||||
if (module->length_size > 3)
|
||||
nal_size = (nal_size << 8)|data[3];
|
||||
if (offset + nal_size > size)
|
||||
nal_size = size - offset;
|
||||
|
||||
offset += nal_size;
|
||||
module->frame_size += nal_size + sizeof(h264_start_code);
|
||||
#ifdef ENABLE_CONTAINERS_LOG_FORMAT_VERBOSE
|
||||
LOG_DEBUG(0, "nal unit size %u", nal_size);
|
||||
#endif
|
||||
}
|
||||
LOG_DEBUG(0, "frame size: %u(%u/%u), pts: %"PRIi64, module->frame_size,
|
||||
size, nal_num, stream->current->pts);
|
||||
|
||||
/* fall through to the next state */
|
||||
module->state = STATE_BUFFER_INIT;
|
||||
|
||||
case STATE_BUFFER_INIT:
|
||||
packet = stream->current;
|
||||
out->size = module->frame_size - module->bytes_read;
|
||||
out->pts = out->dts = VC_CONTAINER_TIME_UNKNOWN;
|
||||
out->flags = VC_CONTAINER_PACKET_FLAG_FRAME_END;
|
||||
|
||||
if (!module->bytes_read)
|
||||
{
|
||||
out->pts = packet->pts;
|
||||
out->dts = packet->dts;
|
||||
out->flags |= VC_CONTAINER_PACKET_FLAG_FRAME_START;
|
||||
}
|
||||
|
||||
if (flags & VC_PACKETIZER_FLAG_INFO)
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
|
||||
if (flags & VC_PACKETIZER_FLAG_SKIP)
|
||||
{
|
||||
/* The easiest is to just drop all the packets belonging to the frame */
|
||||
while (!(stream->current->flags & VC_CONTAINER_PACKET_FLAG_FRAME_END))
|
||||
bytestream_skip_packet(stream);
|
||||
bytestream_skip_packet(stream);
|
||||
|
||||
module->frame_size = 0;
|
||||
module->bytes_read = 0;
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/* We now know that we'll have to read some data so reset the output size */
|
||||
out->size = 0;
|
||||
|
||||
/* Go to the next relevant state */
|
||||
module->state = STATE_NAL_START;
|
||||
if (module->nal_bytes_left || module->bytes_read == module->frame_size)
|
||||
module->state = STATE_NAL_DATA;
|
||||
break;
|
||||
|
||||
case STATE_NAL_START:
|
||||
/* Extract the size of the current NAL */
|
||||
bytestream_get(stream, data, module->length_size);
|
||||
|
||||
module->nal_bytes_left = data[0];
|
||||
if (module->length_size > 1)
|
||||
module->nal_bytes_left = (module->nal_bytes_left << 8)|data[1];
|
||||
if (module->length_size > 2)
|
||||
module->nal_bytes_left = (module->nal_bytes_left << 8)|data[2];
|
||||
if (module->length_size > 3)
|
||||
module->nal_bytes_left = (module->nal_bytes_left << 8)|data[3];
|
||||
|
||||
if (module->bytes_read + module->nal_bytes_left + sizeof(h264_start_code) >
|
||||
module->frame_size)
|
||||
{
|
||||
LOG_ERROR(0, "truncating nal (%u/%u)", module->nal_bytes_left,
|
||||
module->frame_size - module->bytes_read - sizeof(h264_start_code));
|
||||
module->nal_bytes_left = module->frame_size - sizeof(h264_start_code);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_CONTAINERS_LOG_FORMAT_VERBOSE
|
||||
LOG_DEBUG(0, "nal unit size %u", module->nal_bytes_left);
|
||||
#endif
|
||||
|
||||
module->start_code_bytes_left = sizeof(h264_start_code);
|
||||
|
||||
/* fall through to the next state */
|
||||
module->state = STATE_NAL_DATA;
|
||||
|
||||
case STATE_NAL_DATA:
|
||||
/* Start by adding the start code */
|
||||
if (module->start_code_bytes_left)
|
||||
{
|
||||
size = MIN(out->buffer_size - out->size, module->start_code_bytes_left);
|
||||
memcpy(out->data + out->size, h264_start_code + sizeof(h264_start_code) -
|
||||
module->start_code_bytes_left, size);
|
||||
module->start_code_bytes_left -= size;
|
||||
module->bytes_read += size;
|
||||
out->size += size;
|
||||
}
|
||||
|
||||
/* Then append the NAL unit itself */
|
||||
if (module->nal_bytes_left)
|
||||
{
|
||||
size = MIN(out->buffer_size - out->size, module->nal_bytes_left);
|
||||
bytestream_get( stream, out->data + out->size, size );
|
||||
module->nal_bytes_left -= size;
|
||||
module->bytes_read += size;
|
||||
out->size += size;
|
||||
}
|
||||
|
||||
/* Check whether we're done */
|
||||
if (module->bytes_read == module->frame_size)
|
||||
{
|
||||
bytestream_skip_packet(stream);
|
||||
module->state = STATE_FRAME_WAIT;
|
||||
module->frame_size = 0;
|
||||
module->bytes_read = 0;
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
else if (out->buffer_size == out->size)
|
||||
{
|
||||
out->flags &= ~VC_CONTAINER_PACKET_FLAG_FRAME_END;
|
||||
module->state = STATE_BUFFER_INIT;
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/* We're not done, go to the next relevant state */
|
||||
module->state = STATE_NAL_START;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
};
|
||||
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T avc1_packetizer_codecconfig( VC_PACKETIZER_T *p_ctx )
|
||||
{
|
||||
VC_PACKETIZER_MODULE_T *module = p_ctx->priv->module;
|
||||
VC_CONTAINER_STATUS_T status;
|
||||
uint8_t *out, *extra = p_ctx->in->extradata + 5;
|
||||
uint8_t *extra_end = extra + p_ctx->in->extradata_size - 5;
|
||||
unsigned int i, j, nal_size, out_size = 0;
|
||||
|
||||
if (p_ctx->in->extradata_size <= 5 ||
|
||||
p_ctx->in->extradata[0] != 1 /* configurationVersion */)
|
||||
return VC_CONTAINER_ERROR_FORMAT_INVALID;
|
||||
|
||||
status = vc_container_format_extradata_alloc(p_ctx->out, p_ctx->in->extradata_size);
|
||||
if (status != VC_CONTAINER_SUCCESS)
|
||||
return status;
|
||||
|
||||
out = p_ctx->out->extradata;
|
||||
module->length_size = (*(p_ctx->in->extradata + 4) & 0x3) + 1;
|
||||
|
||||
for (i = 0; i < 2 && extra < extra_end - 1; i++)
|
||||
{
|
||||
j = *(extra++) & (!i ? 0x1F : 0xFF);
|
||||
for (; j > 0 && extra < extra_end - 2; j--)
|
||||
{
|
||||
nal_size = (extra[0] << 8) | extra[1]; extra += 2;
|
||||
if (extra + nal_size > extra_end)
|
||||
{
|
||||
extra = extra_end;
|
||||
break;
|
||||
}
|
||||
|
||||
out[0] = out[1] = out[2] = 0; out[3] = 1;
|
||||
memcpy(out + 4, extra, nal_size);
|
||||
out += nal_size + 4; extra += nal_size;
|
||||
out_size += nal_size + 4;
|
||||
}
|
||||
}
|
||||
|
||||
p_ctx->out->extradata_size = out_size;
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_CONTAINER_STATUS_T avc1_packetizer_open( VC_PACKETIZER_T *p_ctx )
|
||||
{
|
||||
VC_PACKETIZER_MODULE_T *module;
|
||||
VC_CONTAINER_STATUS_T status;
|
||||
|
||||
if(p_ctx->in->codec != VC_CONTAINER_CODEC_H264 &&
|
||||
p_ctx->out->codec != VC_CONTAINER_CODEC_H264)
|
||||
return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
if(p_ctx->in->codec_variant != VC_CONTAINER_VARIANT_H264_AVC1 &&
|
||||
p_ctx->out->codec_variant != VC_CONTAINER_VARIANT_H264_DEFAULT)
|
||||
return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
if(!(p_ctx->in->flags & VC_CONTAINER_ES_FORMAT_FLAG_FRAMED))
|
||||
return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
|
||||
p_ctx->priv->module = module = malloc(sizeof(*module));
|
||||
if(!module)
|
||||
return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
|
||||
memset(module, 0, sizeof(*module));
|
||||
|
||||
vc_container_format_copy(p_ctx->out, p_ctx->in, 0);
|
||||
status = avc1_packetizer_codecconfig(p_ctx);
|
||||
if (status != VC_CONTAINER_SUCCESS)
|
||||
{
|
||||
free(module);
|
||||
return status;
|
||||
}
|
||||
|
||||
p_ctx->out->codec_variant = VC_CONTAINER_VARIANT_H264_DEFAULT;
|
||||
p_ctx->max_frame_size = MAX_FRAME_SIZE;
|
||||
p_ctx->priv->pf_close = avc1_packetizer_close;
|
||||
p_ctx->priv->pf_packetize = avc1_packetizer_packetize;
|
||||
p_ctx->priv->pf_reset = avc1_packetizer_reset;
|
||||
LOG_DEBUG(0, "using avc1 video packetizer");
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_PACKETIZER_REGISTER(avc1_packetizer_open, "avc1");
|
154
gfx/include/userland/containers/io/io_file.c
Normal file
154
gfx/include/userland/containers/io/io_file.c
Normal file
@ -0,0 +1,154 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "containers/containers.h"
|
||||
#include "containers/core/containers_common.h"
|
||||
#include "containers/core/containers_io.h"
|
||||
#include "containers/core/containers_uri.h"
|
||||
|
||||
typedef struct VC_CONTAINER_IO_MODULE_T
|
||||
{
|
||||
FILE *stream;
|
||||
|
||||
} VC_CONTAINER_IO_MODULE_T;
|
||||
|
||||
VC_CONTAINER_STATUS_T vc_container_io_file_open( VC_CONTAINER_IO_T *, const char *,
|
||||
VC_CONTAINER_IO_MODE_T );
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T io_file_close( VC_CONTAINER_IO_T *p_ctx )
|
||||
{
|
||||
VC_CONTAINER_IO_MODULE_T *module = p_ctx->module;
|
||||
fclose(module->stream);
|
||||
free(module);
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static size_t io_file_read(VC_CONTAINER_IO_T *p_ctx, void *buffer, size_t size)
|
||||
{
|
||||
size_t ret = fread(buffer, 1, size, p_ctx->module->stream);
|
||||
if(ret != size)
|
||||
{
|
||||
/* Sanity check return value. Some platforms (e.g. Android) can return -1 */
|
||||
if( ((int)ret) < 0 ) ret = 0;
|
||||
|
||||
if( feof(p_ctx->module->stream) ) p_ctx->status = VC_CONTAINER_ERROR_EOS;
|
||||
else p_ctx->status = VC_CONTAINER_ERROR_FAILED;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static size_t io_file_write(VC_CONTAINER_IO_T *p_ctx, const void *buffer, size_t size)
|
||||
{
|
||||
return fwrite(buffer, 1, size, p_ctx->module->stream);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T io_file_seek(VC_CONTAINER_IO_T *p_ctx, int64_t offset)
|
||||
{
|
||||
VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
|
||||
int ret;
|
||||
|
||||
//FIXME: large file support
|
||||
#ifdef _VIDEOCORE
|
||||
extern int fseek64(FILE *fp, int64_t offset, int whence);
|
||||
ret = fseek64(p_ctx->module->stream, offset, SEEK_SET);
|
||||
#else
|
||||
if (offset > (int64_t)UINT_MAX)
|
||||
{
|
||||
p_ctx->status = VC_CONTAINER_ERROR_EOS;
|
||||
return VC_CONTAINER_ERROR_EOS;
|
||||
}
|
||||
ret = fseek(p_ctx->module->stream, (long)offset, SEEK_SET);
|
||||
#endif
|
||||
if(ret)
|
||||
{
|
||||
if( feof(p_ctx->module->stream) ) status = VC_CONTAINER_ERROR_EOS;
|
||||
else status = VC_CONTAINER_ERROR_FAILED;
|
||||
}
|
||||
|
||||
p_ctx->status = status;
|
||||
return status;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_CONTAINER_STATUS_T vc_container_io_file_open( VC_CONTAINER_IO_T *p_ctx,
|
||||
const char *unused, VC_CONTAINER_IO_MODE_T mode )
|
||||
{
|
||||
VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
|
||||
VC_CONTAINER_IO_MODULE_T *module = 0;
|
||||
const char *psz_mode = mode == VC_CONTAINER_IO_MODE_WRITE ? "wb+" : "rb";
|
||||
const char *uri = p_ctx->uri;
|
||||
FILE *stream = 0;
|
||||
VC_CONTAINER_PARAM_UNUSED(unused);
|
||||
|
||||
if(vc_uri_path(p_ctx->uri_parts))
|
||||
uri = vc_uri_path(p_ctx->uri_parts);
|
||||
|
||||
stream = fopen(uri, psz_mode);
|
||||
if(!stream) { status = VC_CONTAINER_ERROR_URI_NOT_FOUND; goto error; }
|
||||
|
||||
/* Turn off buffering. The container layer will provide its own cache */
|
||||
setvbuf(stream, NULL, _IONBF, 0);
|
||||
|
||||
module = malloc( sizeof(*module) );
|
||||
if(!module) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
|
||||
memset(module, 0, sizeof(*module));
|
||||
|
||||
p_ctx->module = module;
|
||||
module->stream = stream;
|
||||
p_ctx->pf_close = io_file_close;
|
||||
p_ctx->pf_read = io_file_read;
|
||||
p_ctx->pf_write = io_file_write;
|
||||
p_ctx->pf_seek = io_file_seek;
|
||||
|
||||
if(mode == VC_CONTAINER_IO_MODE_WRITE)
|
||||
{
|
||||
p_ctx->max_size = (1UL<<31)-1; /* For now limit to 2GB */
|
||||
}
|
||||
else
|
||||
{
|
||||
//FIXME: large file support, platform-specific file size
|
||||
fseek(p_ctx->module->stream, 0, SEEK_END);
|
||||
p_ctx->size = ftell(p_ctx->module->stream);
|
||||
fseek(p_ctx->module->stream, 0, SEEK_SET);
|
||||
}
|
||||
|
||||
p_ctx->capabilities = VC_CONTAINER_IO_CAPS_NO_CACHING;
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
|
||||
error:
|
||||
if(stream) fclose(stream);
|
||||
return status;
|
||||
}
|
898
gfx/include/userland/containers/io/io_http.c
Normal file
898
gfx/include/userland/containers/io/io_http.c
Normal file
@ -0,0 +1,898 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "containers/containers.h"
|
||||
#include "containers/core/containers_common.h"
|
||||
#include "containers/core/containers_io.h"
|
||||
#include "containers/core/containers_uri.h"
|
||||
#include "containers/core/containers_logging.h"
|
||||
#include "containers/core/containers_list.h"
|
||||
#include "containers/core/containers_utils.h"
|
||||
#include "containers/net/net_sockets.h"
|
||||
|
||||
/* Set to 1 if you want to log all HTTP requests */
|
||||
#define ENABLE_HTTP_EXTRA_LOGGING 0
|
||||
|
||||
/******************************************************************************
|
||||
Defines and constants.
|
||||
******************************************************************************/
|
||||
|
||||
#define IO_HTTP_DEFAULT_PORT "80"
|
||||
|
||||
/** Space for sending requests and receiving responses */
|
||||
#define COMMS_BUFFER_SIZE 4000
|
||||
|
||||
/** Largest allowed HTTP URI. Must be substantially smaller than COMMS_BUFFER_SIZE
|
||||
* to allow for the headers that may be sent. */
|
||||
#define HTTP_URI_LENGTH_MAX 1024
|
||||
|
||||
/** Initial capacity of header list */
|
||||
#define HEADER_LIST_INITIAL_CAPACITY 16
|
||||
|
||||
/** Format of the first line of an HTTP request */
|
||||
#define HTTP_REQUEST_LINE_FORMAT "%s %s HTTP/1.1\r\nHost: %s\r\n"
|
||||
|
||||
/** Format of a range request */
|
||||
#define HTTP_RANGE_REQUEST "Range: bytes=%"PRId64"-%"PRId64"\r\n"
|
||||
|
||||
/** Format string for common headers used with all request methods.
|
||||
* Note: includes double new line to terminate headers */
|
||||
#define TRAILING_HEADERS_FORMAT "User-Agent: Broadcom/1.0\r\n\r\n"
|
||||
|
||||
/** \name HTTP methods, used as the first item in the request line
|
||||
* @{ */
|
||||
#define GET_METHOD "GET"
|
||||
#define HEAD_METHOD "HEAD"
|
||||
/* @} */
|
||||
|
||||
/** \name Names of headers used by the code
|
||||
* @{ */
|
||||
#define CONTENT_LENGTH_NAME "Content-Length"
|
||||
#define CONTENT_BASE_NAME "Content-Base"
|
||||
#define CONTENT_LOCATION_NAME "Content-Location"
|
||||
#define ACCEPT_RANGES_NAME "Accept-Ranges"
|
||||
#define CONNECTION_NAME "Connection"
|
||||
/* @} */
|
||||
|
||||
/** Supported HTTP major version number */
|
||||
#define HTTP_MAJOR_VERSION 1
|
||||
/** Supported HTTP minor version number */
|
||||
#define HTTP_MINOR_VERSION 1
|
||||
|
||||
/** Lowest successful status code value */
|
||||
#define HTTP_STATUS_OK 200
|
||||
#define HTTP_STATUS_PARTIAL_CONTENT 206
|
||||
|
||||
typedef struct http_header_tag {
|
||||
const char *name;
|
||||
char *value;
|
||||
} HTTP_HEADER_T;
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
Type definitions
|
||||
******************************************************************************/
|
||||
typedef struct VC_CONTAINER_IO_MODULE_T
|
||||
{
|
||||
VC_CONTAINER_NET_T *sock;
|
||||
VC_CONTAINERS_LIST_T *header_list; /**< Parsed response headers, pointing into comms buffer */
|
||||
|
||||
bool persistent;
|
||||
int64_t cur_offset;
|
||||
bool reconnecting;
|
||||
|
||||
/* Buffer used for sending and receiving HTTP messages */
|
||||
char comms_buffer[COMMS_BUFFER_SIZE];
|
||||
} VC_CONTAINER_IO_MODULE_T;
|
||||
|
||||
/******************************************************************************
|
||||
Function prototypes
|
||||
******************************************************************************/
|
||||
|
||||
static int io_http_header_comparator(const HTTP_HEADER_T *first, const HTTP_HEADER_T *second);
|
||||
static VC_CONTAINER_STATUS_T io_http_send(VC_CONTAINER_IO_T *p_ctx);
|
||||
|
||||
VC_CONTAINER_STATUS_T vc_container_io_http_open(VC_CONTAINER_IO_T *, const char *,
|
||||
VC_CONTAINER_IO_MODE_T);
|
||||
|
||||
/******************************************************************************
|
||||
Local Functions
|
||||
******************************************************************************/
|
||||
|
||||
/**************************************************************************//**
|
||||
* Trim whitespace from the end and start of the string
|
||||
*
|
||||
* \param str String to be trimmed
|
||||
* \return Trimmed string
|
||||
*/
|
||||
static char *io_http_trim(char *str)
|
||||
{
|
||||
char *s = str + strlen(str);
|
||||
|
||||
/* Search backwards for first non-whitespace */
|
||||
while (--s >= str &&(*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r'))
|
||||
; /* Everything done in the while */
|
||||
s[1] = '\0';
|
||||
|
||||
/* Now move start of string forwards to first non-whitespace */
|
||||
s = str;
|
||||
while (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r')
|
||||
s++;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/**************************************************************************//**
|
||||
* Header comparison function.
|
||||
* Compare two header structures and return whether the first is less than,
|
||||
* equal to or greater than the second.
|
||||
*
|
||||
* @param first The first structure to be compared.
|
||||
* @param second The second structure to be compared.
|
||||
* @return Negative if first is less than second, positive if first is greater
|
||||
* and zero if they are equal.
|
||||
*/
|
||||
static int io_http_header_comparator(const HTTP_HEADER_T *first, const HTTP_HEADER_T *second)
|
||||
{
|
||||
return strcasecmp(first->name, second->name);
|
||||
}
|
||||
|
||||
/**************************************************************************//**
|
||||
* Check a response status line to see if the response is usable or not.
|
||||
* Reasons for invalidity include:
|
||||
* - Incorrectly formatted
|
||||
* - Unsupported version
|
||||
* - Status code is not in the 2xx range
|
||||
*
|
||||
* @param status_line The response status line.
|
||||
* @return The resulting status of the function.
|
||||
*/
|
||||
static bool io_http_successful_response_status(const char *status_line)
|
||||
{
|
||||
unsigned int major_version, minor_version, status_code;
|
||||
|
||||
/* coverity[secure_coding] String is null-terminated */
|
||||
if (sscanf(status_line, "HTTP/%u.%u %u", &major_version, &minor_version, &status_code) != 3)
|
||||
{
|
||||
LOG_ERROR(NULL, "HTTP: Invalid response status line:\n%s", status_line);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (major_version != HTTP_MAJOR_VERSION || minor_version != HTTP_MINOR_VERSION)
|
||||
{
|
||||
LOG_ERROR(NULL, "HTTP: Unexpected response HTTP version: %u.%u", major_version, minor_version);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (status_code != HTTP_STATUS_OK && status_code != HTTP_STATUS_PARTIAL_CONTENT)
|
||||
{
|
||||
LOG_ERROR(NULL, "HTTP: Response status unsuccessful:\n%s", status_line);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**************************************************************************//**
|
||||
* Get the content length header from the response headers as an unsigned
|
||||
* 64-bit integer.
|
||||
* If the content length header is not found or badly formatted, zero is
|
||||
* returned.
|
||||
*
|
||||
* @param header_list The response headers.
|
||||
* @return The content length.
|
||||
*/
|
||||
static uint64_t io_http_get_content_length(VC_CONTAINERS_LIST_T *header_list)
|
||||
{
|
||||
uint64_t content_length = 0;
|
||||
HTTP_HEADER_T header;
|
||||
|
||||
header.name = CONTENT_LENGTH_NAME;
|
||||
if (header_list && vc_containers_list_find_entry(header_list, &header))
|
||||
/* coverity[secure_coding] String is null-terminated */
|
||||
sscanf(header.value, "%"PRIu64, &content_length);
|
||||
|
||||
return content_length;
|
||||
}
|
||||
|
||||
/**************************************************************************//**
|
||||
* Get the accept ranges header from the response headers and verify that
|
||||
* the server accepts byte ranges..
|
||||
* If the accept ranges header is not found false is returned.
|
||||
*
|
||||
* @param header_list The response headers.
|
||||
* @return The resulting status of the function.
|
||||
*/
|
||||
static bool io_http_check_accept_range(VC_CONTAINERS_LIST_T *header_list)
|
||||
{
|
||||
HTTP_HEADER_T header;
|
||||
|
||||
header.name = ACCEPT_RANGES_NAME;
|
||||
if (header_list && vc_containers_list_find_entry(header_list, &header))
|
||||
{
|
||||
/* coverity[secure_coding] String is null-terminated */
|
||||
if (!strcasecmp(header.value, "bytes"))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**************************************************************************//**
|
||||
* Check whether the server supports persistent connections.
|
||||
*
|
||||
* @param header_list The response headers.
|
||||
* @return The resulting status of the function.
|
||||
*/
|
||||
static bool io_http_check_persistent_connection(VC_CONTAINERS_LIST_T *header_list)
|
||||
{
|
||||
HTTP_HEADER_T header;
|
||||
|
||||
header.name = CONNECTION_NAME;
|
||||
if (header_list && vc_containers_list_find_entry(header_list, &header))
|
||||
{
|
||||
/* coverity[secure_coding] String is null-terminated */
|
||||
if (!strcasecmp(header.value, "close"))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T translate_net_status_to_container_status(vc_container_net_status_t net_status)
|
||||
{
|
||||
switch (net_status)
|
||||
{
|
||||
case VC_CONTAINER_NET_SUCCESS: return VC_CONTAINER_SUCCESS;
|
||||
case VC_CONTAINER_NET_ERROR_INVALID_SOCKET: return VC_CONTAINER_ERROR_INVALID_ARGUMENT;
|
||||
case VC_CONTAINER_NET_ERROR_NOT_ALLOWED: return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
|
||||
case VC_CONTAINER_NET_ERROR_INVALID_PARAMETER: return VC_CONTAINER_ERROR_INVALID_ARGUMENT;
|
||||
case VC_CONTAINER_NET_ERROR_NO_MEMORY: return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
|
||||
case VC_CONTAINER_NET_ERROR_IN_USE: return VC_CONTAINER_ERROR_URI_OPEN_FAILED;
|
||||
case VC_CONTAINER_NET_ERROR_NETWORK: return VC_CONTAINER_ERROR_EOS;
|
||||
case VC_CONTAINER_NET_ERROR_CONNECTION_LOST: return VC_CONTAINER_ERROR_EOS;
|
||||
case VC_CONTAINER_NET_ERROR_NOT_CONNECTED: return VC_CONTAINER_ERROR_INVALID_ARGUMENT;
|
||||
case VC_CONTAINER_NET_ERROR_TIMED_OUT: return VC_CONTAINER_ERROR_ABORTED;
|
||||
case VC_CONTAINER_NET_ERROR_CONNECTION_REFUSED: return VC_CONTAINER_ERROR_NOT_FOUND;
|
||||
case VC_CONTAINER_NET_ERROR_HOST_NOT_FOUND: return VC_CONTAINER_ERROR_NOT_FOUND;
|
||||
case VC_CONTAINER_NET_ERROR_TRY_AGAIN: return VC_CONTAINER_ERROR_CONTINUE;
|
||||
default: return VC_CONTAINER_ERROR_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T io_http_open_socket(VC_CONTAINER_IO_T *ctx)
|
||||
{
|
||||
VC_CONTAINER_IO_MODULE_T *module = ctx->module;
|
||||
VC_CONTAINER_STATUS_T status;
|
||||
const char *host, *port;
|
||||
|
||||
/* Treat empty host or port strings as not defined */
|
||||
port = vc_uri_port(ctx->uri_parts);
|
||||
if (port && !*port)
|
||||
port = NULL;
|
||||
|
||||
/* Require the port to be defined */
|
||||
if (!port)
|
||||
{
|
||||
status = VC_CONTAINER_ERROR_URI_OPEN_FAILED;
|
||||
goto error;
|
||||
}
|
||||
|
||||
host = vc_uri_host(ctx->uri_parts);
|
||||
if (host && !*host)
|
||||
host = NULL;
|
||||
|
||||
if (!host)
|
||||
{
|
||||
status = VC_CONTAINER_ERROR_URI_OPEN_FAILED;
|
||||
goto error;
|
||||
}
|
||||
|
||||
module->sock = vc_container_net_open(host, port, VC_CONTAINER_NET_OPEN_FLAG_STREAM, NULL);
|
||||
if (!module->sock)
|
||||
{
|
||||
status = VC_CONTAINER_ERROR_URI_NOT_FOUND;
|
||||
goto error;
|
||||
}
|
||||
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
|
||||
error:
|
||||
return status;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T io_http_close_socket(VC_CONTAINER_IO_MODULE_T *module)
|
||||
{
|
||||
if (module->sock)
|
||||
{
|
||||
vc_container_net_close(module->sock);
|
||||
module->sock = NULL;
|
||||
}
|
||||
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static size_t io_http_read_from_net(VC_CONTAINER_IO_T *p_ctx, void *buffer, size_t size)
|
||||
{
|
||||
size_t ret;
|
||||
vc_container_net_status_t net_status;
|
||||
|
||||
ret = vc_container_net_read(p_ctx->module->sock, buffer, size);
|
||||
net_status = vc_container_net_status(p_ctx->module->sock);
|
||||
p_ctx->status = translate_net_status_to_container_status(net_status);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**************************************************************************//**
|
||||
* Reads an HTTP response and parses it into headers and content.
|
||||
* The headers and content remain stored in the comms buffer, but referenced
|
||||
* by the module's header list. Content uses a special header name that cannot
|
||||
* occur in the real headers.
|
||||
*
|
||||
* @param p_ctx The HTTP reader context.
|
||||
* @return The resulting status of the function.
|
||||
*/
|
||||
static VC_CONTAINER_STATUS_T io_http_read_response(VC_CONTAINER_IO_T *p_ctx)
|
||||
{
|
||||
VC_CONTAINER_IO_MODULE_T *module = p_ctx->module;
|
||||
char *next_read = module->comms_buffer;
|
||||
size_t space_available = sizeof(module->comms_buffer) - 1; /* Allow for a NUL */
|
||||
char *ptr = next_read;
|
||||
bool end_response = false;
|
||||
HTTP_HEADER_T header;
|
||||
const char endstr[] = "\r\n\r\n";
|
||||
int endcount = sizeof(endstr) - 1;
|
||||
int endchk = 0;
|
||||
|
||||
vc_containers_list_reset(module->header_list);
|
||||
|
||||
/* Response status line doesn't need to be stored, just checked */
|
||||
header.name = NULL;
|
||||
header.value = next_read;
|
||||
|
||||
/*
|
||||
* We need to read just a byte at a time to make sure that we just read the HTTP response and
|
||||
* no more. For example, if a GET operation was requested the file being fetched will also
|
||||
* be waiting to be read on the socket.
|
||||
*/
|
||||
|
||||
while (space_available)
|
||||
{
|
||||
if (io_http_read_from_net(p_ctx, next_read, 1) != 1)
|
||||
break;
|
||||
|
||||
next_read++;
|
||||
space_available--;
|
||||
|
||||
if (next_read[-1] == endstr[endchk])
|
||||
{
|
||||
if (++endchk == endcount)
|
||||
break;
|
||||
}
|
||||
else
|
||||
endchk = 0;
|
||||
}
|
||||
if (!space_available)
|
||||
{
|
||||
LOG_ERROR(NULL, "comms buffer too small for complete HTTP message (%d)",
|
||||
sizeof(module->comms_buffer));
|
||||
return VC_CONTAINER_ERROR_CORRUPTED;
|
||||
}
|
||||
|
||||
*next_read = '\0';
|
||||
|
||||
if (endchk == endcount)
|
||||
{
|
||||
if (ENABLE_HTTP_EXTRA_LOGGING)
|
||||
LOG_DEBUG(NULL, "READ FROM SERVER: %d bytes\n%s\n-----------------------------------------",
|
||||
sizeof(module->comms_buffer) - 1 - space_available, module->comms_buffer);
|
||||
|
||||
while (!end_response && ptr < next_read)
|
||||
{
|
||||
switch (*ptr)
|
||||
{
|
||||
case ':':
|
||||
if (header.value)
|
||||
{
|
||||
/* Just another character in the value */
|
||||
ptr++;
|
||||
} else {
|
||||
/* End of name, expect value next */
|
||||
*ptr++ = '\0';
|
||||
header.value = ptr;
|
||||
}
|
||||
break;
|
||||
|
||||
case '\n':
|
||||
if (header.value)
|
||||
{
|
||||
/* End of line while parsing the value part of the header, add name/value pair to list */
|
||||
*ptr++ = '\0';
|
||||
header.value = io_http_trim(header.value);
|
||||
if (header.name)
|
||||
{
|
||||
if (!vc_containers_list_insert(module->header_list, &header, false))
|
||||
{
|
||||
LOG_ERROR(NULL, "HTTP: Failed to add <%s> header to list", header.name);
|
||||
return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
} else {
|
||||
/* Check response status line */
|
||||
if (!io_http_successful_response_status(header.value))
|
||||
return VC_CONTAINER_ERROR_FORMAT_INVALID;
|
||||
}
|
||||
/* Ready for next header */
|
||||
header.name = ptr;
|
||||
header.value = NULL;
|
||||
} else {
|
||||
/* End of line while parsing the name of a header */
|
||||
*ptr++ = '\0';
|
||||
if (*header.name && *header.name != '\r')
|
||||
{
|
||||
/* A non-empty name is invalid, so fail */
|
||||
LOG_ERROR(NULL, "HTTP: Invalid name in header - no colon:\n%s", header.name);
|
||||
return VC_CONTAINER_ERROR_FORMAT_INVALID;
|
||||
}
|
||||
|
||||
/* An empty name signifies the end of the HTTP response */
|
||||
end_response = true;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Just another character in either the name or the value */
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!space_available && !end_response)
|
||||
{
|
||||
/* Ran out of buffer space */
|
||||
LOG_ERROR(NULL, "HTTP: Response header section too big");
|
||||
return VC_CONTAINER_ERROR_FORMAT_INVALID;
|
||||
}
|
||||
|
||||
return p_ctx->status;
|
||||
}
|
||||
|
||||
/**************************************************************************//**
|
||||
* Send a GET request to the HTTP server.
|
||||
*
|
||||
* @param p_ctx The reader context.
|
||||
* @return The resulting status of the function.
|
||||
*/
|
||||
static VC_CONTAINER_STATUS_T io_http_send_get_request(VC_CONTAINER_IO_T *p_ctx, size_t size)
|
||||
{
|
||||
VC_CONTAINER_IO_MODULE_T *module = p_ctx->module;
|
||||
char *ptr = module->comms_buffer, *end = ptr + sizeof(module->comms_buffer);
|
||||
int64_t end_offset;
|
||||
|
||||
ptr += snprintf(ptr, end - ptr, HTTP_REQUEST_LINE_FORMAT, GET_METHOD,
|
||||
vc_uri_path(p_ctx->uri_parts), vc_uri_host(p_ctx->uri_parts));
|
||||
|
||||
end_offset = module->cur_offset + size - 1;
|
||||
if (end_offset >= p_ctx->size)
|
||||
end_offset = p_ctx->size - 1;
|
||||
|
||||
if (ptr < end)
|
||||
ptr += snprintf(ptr, end - ptr, HTTP_RANGE_REQUEST, module->cur_offset, end_offset);
|
||||
|
||||
if (ptr < end)
|
||||
ptr += snprintf(ptr, end - ptr, TRAILING_HEADERS_FORMAT);
|
||||
|
||||
if (ptr >= end)
|
||||
{
|
||||
LOG_ERROR(0, "comms buffer too small (%i/%u)", (int)(end - ptr),
|
||||
sizeof(module->comms_buffer));
|
||||
return VC_CONTAINER_ERROR_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
if (ENABLE_HTTP_EXTRA_LOGGING)
|
||||
LOG_DEBUG(NULL, "Sending server read request:\n%s\n---------------------\n", module->comms_buffer);
|
||||
return io_http_send(p_ctx);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T io_http_seek(VC_CONTAINER_IO_T *p_ctx, int64_t offset)
|
||||
{
|
||||
VC_CONTAINER_IO_MODULE_T *module = p_ctx->module;
|
||||
|
||||
/*
|
||||
* No seeking past the end of the file.
|
||||
*/
|
||||
|
||||
if (offset < 0 || offset > p_ctx->size)
|
||||
{
|
||||
p_ctx->status = VC_CONTAINER_ERROR_EOS;
|
||||
return VC_CONTAINER_ERROR_EOS;
|
||||
}
|
||||
|
||||
module->cur_offset = offset;
|
||||
p_ctx->status = VC_CONTAINER_SUCCESS;
|
||||
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T io_http_close(VC_CONTAINER_IO_T *p_ctx)
|
||||
{
|
||||
VC_CONTAINER_IO_MODULE_T *module = p_ctx->module;
|
||||
|
||||
if (!module)
|
||||
return VC_CONTAINER_ERROR_INVALID_ARGUMENT;
|
||||
|
||||
io_http_close_socket(module);
|
||||
if (module->header_list)
|
||||
vc_containers_list_destroy(module->header_list);
|
||||
|
||||
free(module);
|
||||
p_ctx->module = NULL;
|
||||
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static size_t io_http_read(VC_CONTAINER_IO_T *p_ctx, void *buffer, size_t size)
|
||||
{
|
||||
VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
|
||||
VC_CONTAINER_IO_MODULE_T *module = p_ctx->module;
|
||||
size_t content_length;
|
||||
size_t bytes_read;
|
||||
size_t ret = 0;
|
||||
char *ptr = buffer;
|
||||
|
||||
/*
|
||||
* Are we at the end of the file?
|
||||
*/
|
||||
|
||||
if (module->cur_offset >= p_ctx->size)
|
||||
{
|
||||
p_ctx->status = VC_CONTAINER_ERROR_EOS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!module->persistent)
|
||||
{
|
||||
status = io_http_open_socket(p_ctx);
|
||||
if (status != VC_CONTAINER_SUCCESS)
|
||||
{
|
||||
LOG_ERROR(NULL, "Error opening socket for GET request");
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
/* Send GET request and get response */
|
||||
status = io_http_send_get_request(p_ctx, size);
|
||||
if (status != VC_CONTAINER_SUCCESS)
|
||||
{
|
||||
LOG_ERROR(NULL, "Error sending GET request");
|
||||
goto error;
|
||||
}
|
||||
|
||||
status = io_http_read_response(p_ctx);
|
||||
if (status == VC_CONTAINER_ERROR_EOS && !module->reconnecting)
|
||||
{
|
||||
LOG_DEBUG(NULL, "reconnecting");
|
||||
io_http_close_socket(module);
|
||||
status = io_http_open_socket(p_ctx);
|
||||
if (status == VC_CONTAINER_SUCCESS)
|
||||
{
|
||||
module->reconnecting = true;
|
||||
status = io_http_read(p_ctx, buffer, size);
|
||||
module->reconnecting = false;
|
||||
return status;
|
||||
}
|
||||
}
|
||||
if (status != VC_CONTAINER_SUCCESS)
|
||||
{
|
||||
LOG_ERROR(NULL, "Error reading GET response");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/*
|
||||
* How much data is the server offering us?
|
||||
*/
|
||||
|
||||
content_length = (size_t)io_http_get_content_length(module->header_list);
|
||||
if (content_length > size)
|
||||
{
|
||||
LOG_ERROR(NULL, "received too much data (%i/%i)",
|
||||
(int)content_length, (int)size);
|
||||
status = VC_CONTAINER_ERROR_CORRUPTED;
|
||||
goto error;
|
||||
}
|
||||
|
||||
bytes_read = 0;
|
||||
while (bytes_read < content_length && p_ctx->status == VC_CONTAINER_SUCCESS)
|
||||
{
|
||||
ret = io_http_read_from_net(p_ctx, ptr, content_length - bytes_read);
|
||||
if (p_ctx->status == VC_CONTAINER_SUCCESS)
|
||||
{
|
||||
bytes_read += ret;
|
||||
ptr += ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (p_ctx->status == VC_CONTAINER_SUCCESS)
|
||||
{
|
||||
module->cur_offset += bytes_read;
|
||||
ret = bytes_read;
|
||||
}
|
||||
|
||||
if (!module->persistent)
|
||||
io_http_close_socket(module);
|
||||
|
||||
return ret;
|
||||
|
||||
error:
|
||||
if (!module->persistent)
|
||||
io_http_close_socket(module);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static size_t io_http_write(VC_CONTAINER_IO_T *p_ctx, const void *buffer, size_t size)
|
||||
{
|
||||
size_t ret = vc_container_net_write(p_ctx->module->sock, buffer, size);
|
||||
vc_container_net_status_t net_status;
|
||||
|
||||
net_status = vc_container_net_status(p_ctx->module->sock);
|
||||
p_ctx->status = translate_net_status_to_container_status(net_status);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T io_http_control(struct VC_CONTAINER_IO_T *p_ctx,
|
||||
VC_CONTAINER_CONTROL_T operation,
|
||||
va_list args)
|
||||
{
|
||||
vc_container_net_status_t net_status;
|
||||
VC_CONTAINER_STATUS_T status;
|
||||
|
||||
switch (operation)
|
||||
{
|
||||
case VC_CONTAINER_CONTROL_IO_SET_READ_BUFFER_SIZE:
|
||||
net_status = vc_container_net_control(p_ctx->module->sock, VC_CONTAINER_NET_CONTROL_SET_READ_BUFFER_SIZE, args);
|
||||
break;
|
||||
case VC_CONTAINER_CONTROL_IO_SET_READ_TIMEOUT_MS:
|
||||
net_status = vc_container_net_control(p_ctx->module->sock, VC_CONTAINER_NET_CONTROL_SET_READ_TIMEOUT_MS, args);
|
||||
break;
|
||||
default:
|
||||
net_status = VC_CONTAINER_NET_ERROR_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
status = translate_net_status_to_container_status(net_status);
|
||||
p_ctx->status = status;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**************************************************************************//**
|
||||
* Send out the data in the comms buffer.
|
||||
*
|
||||
* @param p_ctx The reader context.
|
||||
* @return The resulting status of the function.
|
||||
*/
|
||||
static VC_CONTAINER_STATUS_T io_http_send(VC_CONTAINER_IO_T *p_ctx)
|
||||
{
|
||||
VC_CONTAINER_IO_MODULE_T *module = p_ctx->module;
|
||||
size_t to_write;
|
||||
size_t written;
|
||||
const char *buffer = module->comms_buffer;
|
||||
|
||||
to_write = strlen(buffer);
|
||||
|
||||
while (to_write)
|
||||
{
|
||||
written = io_http_write(p_ctx, buffer, to_write);
|
||||
if (p_ctx->status != VC_CONTAINER_SUCCESS)
|
||||
break;
|
||||
|
||||
to_write -= written;
|
||||
buffer += written;
|
||||
}
|
||||
|
||||
return p_ctx->status;
|
||||
}
|
||||
|
||||
/**************************************************************************//**
|
||||
* Send a HEAD request to the HTTP server.
|
||||
*
|
||||
* @param p_ctx The reader context.
|
||||
* @return The resulting status of the function.
|
||||
*/
|
||||
static VC_CONTAINER_STATUS_T io_http_send_head_request(VC_CONTAINER_IO_T *p_ctx)
|
||||
{
|
||||
VC_CONTAINER_IO_MODULE_T *module = p_ctx->module;
|
||||
char *ptr = module->comms_buffer, *end = ptr + sizeof(module->comms_buffer);
|
||||
|
||||
ptr += snprintf(ptr, end - ptr, HTTP_REQUEST_LINE_FORMAT, HEAD_METHOD,
|
||||
vc_uri_path(p_ctx->uri_parts), vc_uri_host(p_ctx->uri_parts));
|
||||
if (ptr < end)
|
||||
ptr += snprintf(ptr, end - ptr, TRAILING_HEADERS_FORMAT);
|
||||
|
||||
if (ptr >= end)
|
||||
{
|
||||
LOG_ERROR(0, "comms buffer too small (%i/%u)", (int)(end - ptr),
|
||||
sizeof(module->comms_buffer));
|
||||
return VC_CONTAINER_ERROR_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
return io_http_send(p_ctx);
|
||||
}
|
||||
|
||||
static VC_CONTAINER_STATUS_T io_http_head(VC_CONTAINER_IO_T *p_ctx)
|
||||
{
|
||||
VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
|
||||
VC_CONTAINER_IO_MODULE_T *module = p_ctx->module;
|
||||
uint64_t content_length;
|
||||
|
||||
/* Send HEAD request and get response */
|
||||
status = io_http_send_head_request(p_ctx);
|
||||
if (status != VC_CONTAINER_SUCCESS)
|
||||
return status;
|
||||
status = io_http_read_response(p_ctx);
|
||||
if (status != VC_CONTAINER_SUCCESS)
|
||||
return status;
|
||||
|
||||
/*
|
||||
* Save the content length since that's our file size.
|
||||
*/
|
||||
|
||||
content_length = io_http_get_content_length(module->header_list);
|
||||
if (content_length)
|
||||
{
|
||||
p_ctx->size = content_length;
|
||||
LOG_DEBUG(NULL, "File size is %"PRId64, p_ctx->size);
|
||||
}
|
||||
|
||||
/*
|
||||
* Now make sure that the server supports byte range requests.
|
||||
*/
|
||||
|
||||
if (!io_http_check_accept_range(module->header_list))
|
||||
{
|
||||
LOG_ERROR(NULL, "Server doesn't support byte range requests");
|
||||
return VC_CONTAINER_ERROR_FAILED;
|
||||
}
|
||||
|
||||
/*
|
||||
* Does it support persistent connections?
|
||||
*/
|
||||
|
||||
if (io_http_check_persistent_connection(module->header_list))
|
||||
{
|
||||
module->persistent = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_DEBUG(NULL, "Server does not support persistent connections");
|
||||
io_http_close_socket(module);
|
||||
}
|
||||
|
||||
module->cur_offset = 0;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
Functions exported as part of the I/O Module API
|
||||
*****************************************************************************/
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_CONTAINER_STATUS_T vc_container_io_http_open(VC_CONTAINER_IO_T *p_ctx,
|
||||
const char *unused, VC_CONTAINER_IO_MODE_T mode)
|
||||
{
|
||||
VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
|
||||
VC_CONTAINER_IO_MODULE_T *module = 0;
|
||||
VC_CONTAINER_PARAM_UNUSED(unused);
|
||||
|
||||
/* Check the URI to see if we're dealing with an http stream */
|
||||
if (!vc_uri_scheme(p_ctx->uri_parts) ||
|
||||
strcasecmp(vc_uri_scheme(p_ctx->uri_parts), "http"))
|
||||
return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
|
||||
/*
|
||||
* Some basic error checking.
|
||||
*/
|
||||
|
||||
if (mode == VC_CONTAINER_IO_MODE_WRITE)
|
||||
{
|
||||
status = VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (strlen(p_ctx->uri) > HTTP_URI_LENGTH_MAX)
|
||||
{
|
||||
status = VC_CONTAINER_ERROR_URI_OPEN_FAILED;
|
||||
goto error;
|
||||
}
|
||||
|
||||
module = calloc(1, sizeof(*module));
|
||||
if (!module)
|
||||
{
|
||||
status = VC_CONTAINER_ERROR_OUT_OF_MEMORY;
|
||||
goto error;
|
||||
}
|
||||
p_ctx->module = module;
|
||||
|
||||
/* header_list will contain pointers into the response_buffer, so take care in re-use */
|
||||
module->header_list = vc_containers_list_create(HEADER_LIST_INITIAL_CAPACITY, sizeof(HTTP_HEADER_T),
|
||||
(VC_CONTAINERS_LIST_COMPARATOR_T)io_http_header_comparator);
|
||||
if (!module->header_list)
|
||||
{
|
||||
status = VC_CONTAINER_ERROR_OUT_OF_MEMORY;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure that we have a port number.
|
||||
*/
|
||||
|
||||
if (vc_uri_port(p_ctx->uri_parts) == NULL)
|
||||
vc_uri_set_port(p_ctx->uri_parts, IO_HTTP_DEFAULT_PORT);
|
||||
|
||||
status = io_http_open_socket(p_ctx);
|
||||
if (status != VC_CONTAINER_SUCCESS)
|
||||
goto error;
|
||||
|
||||
/*
|
||||
* Whoo hoo! Our socket is open. Now let's send a HEAD request.
|
||||
*/
|
||||
|
||||
status = io_http_head(p_ctx);
|
||||
if (status != VC_CONTAINER_SUCCESS)
|
||||
goto error;
|
||||
|
||||
p_ctx->pf_close = io_http_close;
|
||||
p_ctx->pf_read = io_http_read;
|
||||
p_ctx->pf_write = NULL;
|
||||
p_ctx->pf_control = io_http_control;
|
||||
p_ctx->pf_seek = io_http_seek;
|
||||
|
||||
p_ctx->capabilities = VC_CONTAINER_IO_CAPS_NO_CACHING;
|
||||
p_ctx->capabilities |= VC_CONTAINER_IO_CAPS_SEEK_SLOW;
|
||||
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
|
||||
error:
|
||||
io_http_close(p_ctx);
|
||||
return status;
|
||||
}
|
379
gfx/include/userland/containers/io/io_net.c
Normal file
379
gfx/include/userland/containers/io/io_net.c
Normal file
@ -0,0 +1,379 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "containers/containers.h"
|
||||
#include "containers/core/containers_common.h"
|
||||
#include "containers/core/containers_io.h"
|
||||
#include "containers/core/containers_uri.h"
|
||||
#include "containers/net/net_sockets.h"
|
||||
|
||||
/* Uncomment this macro definition to capture data read and written through this interface */
|
||||
/* #define IO_NET_CAPTURE_PACKETS */
|
||||
|
||||
#ifdef IO_NET_CAPTURE_PACKETS
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef ENABLE_CONTAINERS_STANDALONE
|
||||
#ifdef _MSC_VER
|
||||
#define IO_NET_CAPTURE_PREFIX "C:\\"
|
||||
#else /* !_MSC_VER */
|
||||
#define IO_NET_CAPTURE_PREFIX "~/"
|
||||
#endif
|
||||
#else /* !ENABLE_CONTAINERS_STANDALONE */
|
||||
#define IO_NET_CAPTURE_PREFIX "/mfs/sd/"
|
||||
#endif
|
||||
|
||||
#define IO_NET_CAPTURE_READ_FILE "capture_read_%s_%s%c.pkt"
|
||||
#define IO_NET_CAPTURE_WRITE_FILE "capture_write_%s_%s%c.pkt"
|
||||
#define IO_NET_CAPTURE_READ_FORMAT IO_NET_CAPTURE_PREFIX IO_NET_CAPTURE_READ_FILE
|
||||
#define IO_NET_CAPTURE_WRITE_FORMAT IO_NET_CAPTURE_PREFIX IO_NET_CAPTURE_WRITE_FILE
|
||||
|
||||
#define CAPTURE_FILENAME_BUFFER_SIZE 300
|
||||
|
||||
#define CAPTURE_BUFFER_SIZE 65536
|
||||
|
||||
/** Native byte order word */
|
||||
#define NATIVE_BYTE_ORDER 0x50415753
|
||||
#endif
|
||||
|
||||
/******************************************************************************
|
||||
Defines and constants.
|
||||
******************************************************************************/
|
||||
|
||||
/******************************************************************************
|
||||
Type definitions
|
||||
******************************************************************************/
|
||||
typedef struct VC_CONTAINER_IO_MODULE_T
|
||||
{
|
||||
VC_CONTAINER_NET_T *sock;
|
||||
#ifdef IO_NET_CAPTURE_PACKETS
|
||||
FILE *read_capture_file;
|
||||
FILE *write_capture_file;
|
||||
#endif
|
||||
} VC_CONTAINER_IO_MODULE_T;
|
||||
|
||||
/** List of recognised network URI schemes (TCP or UDP).
|
||||
* Note: always use lower case for the scheme name. */
|
||||
static struct
|
||||
{
|
||||
const char *scheme;
|
||||
bool is_udp;
|
||||
} recognised_schemes[] = {
|
||||
{ "rtp:", true },
|
||||
{ "rtsp:", false },
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
Function prototypes
|
||||
******************************************************************************/
|
||||
VC_CONTAINER_STATUS_T vc_container_io_net_open( VC_CONTAINER_IO_T *, const char *,
|
||||
VC_CONTAINER_IO_MODE_T );
|
||||
|
||||
/******************************************************************************
|
||||
Local Functions
|
||||
******************************************************************************/
|
||||
|
||||
#ifdef IO_NET_CAPTURE_PACKETS
|
||||
/*****************************************************************************/
|
||||
static FILE *io_net_open_capture_file(const char *host_str,
|
||||
const char *port_str,
|
||||
bool is_udp,
|
||||
VC_CONTAINER_IO_MODE_T mode)
|
||||
{
|
||||
char filename[CAPTURE_FILENAME_BUFFER_SIZE];
|
||||
const char *format;
|
||||
FILE *stream = NULL;
|
||||
uint32_t byte_order = NATIVE_BYTE_ORDER;
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case VC_CONTAINER_IO_MODE_WRITE:
|
||||
format = IO_NET_CAPTURE_WRITE_FORMAT;
|
||||
break;
|
||||
case VC_CONTAINER_IO_MODE_READ:
|
||||
format = IO_NET_CAPTURE_READ_FORMAT;
|
||||
break;
|
||||
default:
|
||||
/* Invalid mode */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!host_str)
|
||||
host_str = "";
|
||||
if (!port_str)
|
||||
port_str = "";
|
||||
|
||||
/* Check filename will fit in buffer */
|
||||
if (strlen(format) + strlen(host_str) + strlen(port_str) - 4 > CAPTURE_FILENAME_BUFFER_SIZE)
|
||||
return NULL;
|
||||
|
||||
/* Create the file */
|
||||
sprintf(filename, format, host_str, port_str, is_udp ? 'u' : 't');
|
||||
stream = fopen(filename, "wb");
|
||||
if (!stream)
|
||||
return NULL;
|
||||
|
||||
/* Buffer plenty of data at a time, if possible */
|
||||
setvbuf(stream, NULL, _IOFBF, CAPTURE_BUFFER_SIZE);
|
||||
|
||||
/* Start file with a byte order marker */
|
||||
if (fwrite(&byte_order, 1, sizeof(byte_order), stream) != sizeof(byte_order))
|
||||
{
|
||||
/* Failed to write even just the byte order mark - abort */
|
||||
fclose(stream);
|
||||
stream = NULL;
|
||||
remove(filename);
|
||||
}
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static void io_net_capture_write_packet( FILE *stream,
|
||||
const char *buffer,
|
||||
uint32_t buffer_size )
|
||||
{
|
||||
if (stream && buffer && buffer_size)
|
||||
{
|
||||
fwrite(&buffer_size, 1, sizeof(buffer_size), stream);
|
||||
fwrite(buffer, 1, buffer_size, stream);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
static bool io_net_recognise_scheme(const char *uri, bool *is_udp)
|
||||
{
|
||||
size_t ii;
|
||||
const char *scheme;
|
||||
|
||||
if (!uri)
|
||||
return false;
|
||||
|
||||
for (ii = 0; ii < countof(recognised_schemes); ii++)
|
||||
{
|
||||
scheme = recognised_schemes[ii].scheme;
|
||||
if (strncmp(scheme, uri, strlen(scheme)) == 0)
|
||||
{
|
||||
*is_udp = recognised_schemes[ii].is_udp;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T translate_net_status_to_container_status(vc_container_net_status_t net_status)
|
||||
{
|
||||
switch (net_status)
|
||||
{
|
||||
case VC_CONTAINER_NET_SUCCESS: return VC_CONTAINER_SUCCESS;
|
||||
case VC_CONTAINER_NET_ERROR_INVALID_SOCKET: return VC_CONTAINER_ERROR_INVALID_ARGUMENT;
|
||||
case VC_CONTAINER_NET_ERROR_NOT_ALLOWED: return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
|
||||
case VC_CONTAINER_NET_ERROR_INVALID_PARAMETER: return VC_CONTAINER_ERROR_INVALID_ARGUMENT;
|
||||
case VC_CONTAINER_NET_ERROR_NO_MEMORY: return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
|
||||
case VC_CONTAINER_NET_ERROR_IN_USE: return VC_CONTAINER_ERROR_URI_OPEN_FAILED;
|
||||
case VC_CONTAINER_NET_ERROR_NETWORK: return VC_CONTAINER_ERROR_EOS;
|
||||
case VC_CONTAINER_NET_ERROR_CONNECTION_LOST: return VC_CONTAINER_ERROR_EOS;
|
||||
case VC_CONTAINER_NET_ERROR_NOT_CONNECTED: return VC_CONTAINER_ERROR_INVALID_ARGUMENT;
|
||||
case VC_CONTAINER_NET_ERROR_TIMED_OUT: return VC_CONTAINER_ERROR_ABORTED;
|
||||
case VC_CONTAINER_NET_ERROR_CONNECTION_REFUSED: return VC_CONTAINER_ERROR_NOT_FOUND;
|
||||
case VC_CONTAINER_NET_ERROR_HOST_NOT_FOUND: return VC_CONTAINER_ERROR_NOT_FOUND;
|
||||
case VC_CONTAINER_NET_ERROR_TRY_AGAIN: return VC_CONTAINER_ERROR_CONTINUE;
|
||||
default: return VC_CONTAINER_ERROR_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T io_net_close( VC_CONTAINER_IO_T *p_ctx )
|
||||
{
|
||||
VC_CONTAINER_IO_MODULE_T *module = p_ctx->module;
|
||||
|
||||
if (!module)
|
||||
return VC_CONTAINER_ERROR_INVALID_ARGUMENT;
|
||||
|
||||
if (module->sock)
|
||||
vc_container_net_close(module->sock);
|
||||
#ifdef IO_NET_CAPTURE_PACKETS
|
||||
if (module->read_capture_file)
|
||||
fclose(module->read_capture_file);
|
||||
if (module->write_capture_file)
|
||||
fclose(module->write_capture_file);
|
||||
#endif
|
||||
free(module);
|
||||
p_ctx->module = NULL;
|
||||
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static size_t io_net_read(VC_CONTAINER_IO_T *p_ctx, void *buffer, size_t size)
|
||||
{
|
||||
size_t ret = vc_container_net_read(p_ctx->module->sock, buffer, size);
|
||||
vc_container_net_status_t net_status;
|
||||
|
||||
net_status = vc_container_net_status(p_ctx->module->sock);
|
||||
p_ctx->status = translate_net_status_to_container_status(net_status);
|
||||
|
||||
#ifdef IO_NET_CAPTURE_PACKETS
|
||||
if (p_ctx->status == VC_CONTAINER_SUCCESS)
|
||||
io_net_capture_write_packet(p_ctx->module->read_capture_file, (const char *)buffer, ret);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static size_t io_net_write(VC_CONTAINER_IO_T *p_ctx, const void *buffer, size_t size)
|
||||
{
|
||||
size_t ret = vc_container_net_write(p_ctx->module->sock, buffer, size);
|
||||
vc_container_net_status_t net_status;
|
||||
|
||||
net_status = vc_container_net_status(p_ctx->module->sock);
|
||||
p_ctx->status = translate_net_status_to_container_status(net_status);
|
||||
|
||||
#ifdef IO_NET_CAPTURE_PACKETS
|
||||
if (p_ctx->status == VC_CONTAINER_SUCCESS)
|
||||
io_net_capture_write_packet(p_ctx->module->write_capture_file, (const char *)buffer, ret);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T io_net_control(struct VC_CONTAINER_IO_T *p_ctx,
|
||||
VC_CONTAINER_CONTROL_T operation,
|
||||
va_list args)
|
||||
{
|
||||
vc_container_net_status_t net_status;
|
||||
VC_CONTAINER_STATUS_T status;
|
||||
|
||||
switch (operation)
|
||||
{
|
||||
case VC_CONTAINER_CONTROL_IO_SET_READ_BUFFER_SIZE:
|
||||
net_status = vc_container_net_control(p_ctx->module->sock, VC_CONTAINER_NET_CONTROL_SET_READ_BUFFER_SIZE, args);
|
||||
break;
|
||||
case VC_CONTAINER_CONTROL_IO_SET_READ_TIMEOUT_MS:
|
||||
net_status = vc_container_net_control(p_ctx->module->sock, VC_CONTAINER_NET_CONTROL_SET_READ_TIMEOUT_MS, args);
|
||||
break;
|
||||
default:
|
||||
net_status = VC_CONTAINER_NET_ERROR_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
status = translate_net_status_to_container_status(net_status);
|
||||
p_ctx->status = status;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T io_net_open_socket(VC_CONTAINER_IO_T *ctx,
|
||||
VC_CONTAINER_IO_MODE_T mode, bool is_udp)
|
||||
{
|
||||
VC_CONTAINER_IO_MODULE_T *module = ctx->module;
|
||||
VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
|
||||
const char *host, *port;
|
||||
|
||||
/* Treat empty host or port strings as not defined */
|
||||
port = vc_uri_port(ctx->uri_parts);
|
||||
if (port && !*port)
|
||||
port = NULL;
|
||||
|
||||
/* Require the port to be defined */
|
||||
if (!port) { status = VC_CONTAINER_ERROR_URI_OPEN_FAILED; goto error; }
|
||||
|
||||
host = vc_uri_host(ctx->uri_parts);
|
||||
if (host && !*host)
|
||||
host = NULL;
|
||||
|
||||
if (!host)
|
||||
{
|
||||
/* TCP servers cannot be handled by this interface and UDP senders need a target */
|
||||
if (!is_udp || mode == VC_CONTAINER_IO_MODE_WRITE)
|
||||
{
|
||||
status = VC_CONTAINER_ERROR_URI_OPEN_FAILED;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
module->sock = vc_container_net_open(host, port, is_udp ? 0 : VC_CONTAINER_NET_OPEN_FLAG_STREAM, NULL);
|
||||
if (!module->sock) { status = VC_CONTAINER_ERROR_URI_NOT_FOUND; goto error; }
|
||||
|
||||
#ifdef IO_NET_CAPTURE_PACKETS
|
||||
if (!is_udp || mode == VC_CONTAINER_IO_MODE_READ)
|
||||
module->read_capture_file = io_net_open_capture_file(host, port, is_udp, VC_CONTAINER_IO_MODE_READ);
|
||||
if (!is_udp || mode == VC_CONTAINER_IO_MODE_WRITE)
|
||||
module->write_capture_file = io_net_open_capture_file(host, port, is_udp, VC_CONTAINER_IO_MODE_WRITE);
|
||||
#endif
|
||||
|
||||
error:
|
||||
return status;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
Functions exported as part of the I/O Module API
|
||||
*****************************************************************************/
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_CONTAINER_STATUS_T vc_container_io_net_open( VC_CONTAINER_IO_T *p_ctx,
|
||||
const char *unused, VC_CONTAINER_IO_MODE_T mode )
|
||||
{
|
||||
VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
|
||||
VC_CONTAINER_IO_MODULE_T *module = 0;
|
||||
bool is_udp;
|
||||
VC_CONTAINER_PARAM_UNUSED(unused);
|
||||
|
||||
if (!io_net_recognise_scheme(p_ctx->uri, &is_udp))
|
||||
{ status = VC_CONTAINER_ERROR_URI_NOT_FOUND; goto error; }
|
||||
|
||||
module = (VC_CONTAINER_IO_MODULE_T *)malloc( sizeof(*module) );
|
||||
if (!module) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
|
||||
memset(module, 0, sizeof(*module));
|
||||
p_ctx->module = module;
|
||||
|
||||
status = io_net_open_socket(p_ctx, mode, is_udp);
|
||||
if (status != VC_CONTAINER_SUCCESS)
|
||||
goto error;
|
||||
|
||||
p_ctx->pf_close = io_net_close;
|
||||
p_ctx->pf_read = io_net_read;
|
||||
p_ctx->pf_write = io_net_write;
|
||||
p_ctx->pf_control = io_net_control;
|
||||
|
||||
/* Disable caching, as this will block waiting for enough data to fill the cache or an error */
|
||||
p_ctx->capabilities = VC_CONTAINER_IO_CAPS_CANT_SEEK;
|
||||
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
|
||||
error:
|
||||
io_net_close(p_ctx);
|
||||
return status;
|
||||
}
|
91
gfx/include/userland/containers/io/io_null.c
Normal file
91
gfx/include/userland/containers/io/io_null.c
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "containers/containers.h"
|
||||
#include "containers/core/containers_common.h"
|
||||
#include "containers/core/containers_io.h"
|
||||
#include "containers/core/containers_uri.h"
|
||||
|
||||
VC_CONTAINER_STATUS_T vc_container_io_null_open( VC_CONTAINER_IO_T *, const char *,
|
||||
VC_CONTAINER_IO_MODE_T );
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T io_null_close( VC_CONTAINER_IO_T *p_ctx )
|
||||
{
|
||||
VC_CONTAINER_PARAM_UNUSED(p_ctx);
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static size_t io_null_read(VC_CONTAINER_IO_T *p_ctx, void *buffer, size_t size)
|
||||
{
|
||||
VC_CONTAINER_PARAM_UNUSED(p_ctx);
|
||||
VC_CONTAINER_PARAM_UNUSED(buffer);
|
||||
VC_CONTAINER_PARAM_UNUSED(size);
|
||||
return size;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static size_t io_null_write(VC_CONTAINER_IO_T *p_ctx, const void *buffer, size_t size)
|
||||
{
|
||||
VC_CONTAINER_PARAM_UNUSED(p_ctx);
|
||||
VC_CONTAINER_PARAM_UNUSED(buffer);
|
||||
VC_CONTAINER_PARAM_UNUSED(size);
|
||||
return size;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T io_null_seek(VC_CONTAINER_IO_T *p_ctx, int64_t offset)
|
||||
{
|
||||
VC_CONTAINER_PARAM_UNUSED(p_ctx);
|
||||
VC_CONTAINER_PARAM_UNUSED(offset);
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_CONTAINER_STATUS_T vc_container_io_null_open( VC_CONTAINER_IO_T *p_ctx,
|
||||
const char *unused, VC_CONTAINER_IO_MODE_T mode )
|
||||
{
|
||||
VC_CONTAINER_PARAM_UNUSED(unused);
|
||||
VC_CONTAINER_PARAM_UNUSED(mode);
|
||||
|
||||
/* Check the URI */
|
||||
if (!vc_uri_scheme(p_ctx->uri_parts) ||
|
||||
(strcasecmp(vc_uri_scheme(p_ctx->uri_parts), "null") &&
|
||||
strcasecmp(vc_uri_scheme(p_ctx->uri_parts), "null")))
|
||||
return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
|
||||
p_ctx->pf_close = io_null_close;
|
||||
p_ctx->pf_read = io_null_read;
|
||||
p_ctx->pf_write = io_null_write;
|
||||
p_ctx->pf_seek = io_null_seek;
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
261
gfx/include/userland/containers/io/io_pktfile.c
Normal file
261
gfx/include/userland/containers/io/io_pktfile.c
Normal file
@ -0,0 +1,261 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "containers/containers.h"
|
||||
#include "containers/core/containers_common.h"
|
||||
#include "containers/core/containers_io.h"
|
||||
#include "containers/core/containers_uri.h"
|
||||
|
||||
/** Native byte order word */
|
||||
#define NATIVE_BYTE_ORDER 0x50415753
|
||||
/** Reverse of native byte order - need to swap bytes around */
|
||||
#define SWAP_BYTE_ORDER 0x53574150
|
||||
|
||||
typedef struct VC_CONTAINER_IO_MODULE_T
|
||||
{
|
||||
FILE *stream;
|
||||
bool is_native_order;
|
||||
} VC_CONTAINER_IO_MODULE_T;
|
||||
|
||||
/** List of recognised schemes.
|
||||
* Note: always use lower case for the scheme name. */
|
||||
static const char * recognised_schemes[] = {
|
||||
"rtp", "rtppkt", "rtsp", "rtsppkt", "pktfile",
|
||||
};
|
||||
|
||||
VC_CONTAINER_STATUS_T vc_container_io_pktfile_open( VC_CONTAINER_IO_T *, const char *,
|
||||
VC_CONTAINER_IO_MODE_T );
|
||||
|
||||
/*****************************************************************************/
|
||||
static bool recognise_scheme(const char *scheme)
|
||||
{
|
||||
size_t ii;
|
||||
|
||||
if (!scheme)
|
||||
return false;
|
||||
|
||||
for (ii = 0; ii < countof(recognised_schemes); ii++)
|
||||
{
|
||||
if (strcmp(recognised_schemes[ii], scheme) == 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static uint32_t swap_byte_order( uint32_t value )
|
||||
{
|
||||
/* Reverse the order of the bytes in the word */
|
||||
return ((value << 24) | ((value & 0xFF00) << 8) | ((value >> 8) & 0xFF00) | (value >> 24));
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T io_pktfile_close( VC_CONTAINER_IO_T *p_ctx )
|
||||
{
|
||||
VC_CONTAINER_IO_MODULE_T *module = p_ctx->module;
|
||||
fclose(module->stream);
|
||||
free(module);
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static size_t io_pktfile_read(VC_CONTAINER_IO_T *p_ctx, void *buffer, size_t size)
|
||||
{
|
||||
VC_CONTAINER_IO_MODULE_T *module = p_ctx->module;
|
||||
uint32_t length = 0;
|
||||
size_t ret;
|
||||
|
||||
ret = fread(&length, 1, sizeof(length), module->stream);
|
||||
if (ret != sizeof(length))
|
||||
{
|
||||
if( feof(module->stream) ) p_ctx->status = VC_CONTAINER_ERROR_EOS;
|
||||
else p_ctx->status = VC_CONTAINER_ERROR_FAILED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!module->is_native_order)
|
||||
length = swap_byte_order(length);
|
||||
|
||||
if (length > 1<<20)
|
||||
{
|
||||
p_ctx->status = VC_CONTAINER_ERROR_FAILED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (size > length)
|
||||
size = length;
|
||||
ret = fread(buffer, 1, size, module->stream);
|
||||
if(ret != size)
|
||||
{
|
||||
if( feof(module->stream) ) p_ctx->status = VC_CONTAINER_ERROR_EOS;
|
||||
else p_ctx->status = VC_CONTAINER_ERROR_FAILED;
|
||||
}
|
||||
else if (length > size)
|
||||
{
|
||||
/* Not enough space to read all the packet, so skip to the next one. */
|
||||
length -= size;
|
||||
vc_container_assert((long)length > 0);
|
||||
fseek(module->stream, (long)length, SEEK_CUR);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static size_t io_pktfile_write(VC_CONTAINER_IO_T *p_ctx, const void *buffer, size_t size)
|
||||
{
|
||||
uint32_t size_word;
|
||||
size_t ret;
|
||||
|
||||
if (size >= 0xFFFFFFFFUL)
|
||||
size_word = 0xFFFFFFFFUL;
|
||||
else
|
||||
size_word = (uint32_t)size;
|
||||
|
||||
ret = fwrite(&size_word, 1, sizeof(size_word), p_ctx->module->stream);
|
||||
if (ret != sizeof(size_word))
|
||||
{
|
||||
p_ctx->status = VC_CONTAINER_ERROR_FAILED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = fwrite(buffer, 1, size_word, p_ctx->module->stream);
|
||||
if (ret != size_word)
|
||||
p_ctx->status = VC_CONTAINER_ERROR_FAILED;
|
||||
if (fflush(p_ctx->module->stream) != 0)
|
||||
p_ctx->status = VC_CONTAINER_ERROR_FAILED;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static FILE *open_file(VC_CONTAINER_IO_T *ctx, VC_CONTAINER_IO_MODE_T mode,
|
||||
VC_CONTAINER_STATUS_T *p_status)
|
||||
{
|
||||
const char *psz_mode = mode == VC_CONTAINER_IO_MODE_WRITE ? "wb+" : "rb";
|
||||
FILE *stream = 0;
|
||||
const char *port, *path;
|
||||
|
||||
/* Treat empty port or path strings as not defined */
|
||||
port = vc_uri_port(ctx->uri_parts);
|
||||
if (port && !*port)
|
||||
port = NULL;
|
||||
|
||||
path = vc_uri_path(ctx->uri_parts);
|
||||
if (path && !*path)
|
||||
path = NULL;
|
||||
|
||||
/* Require the port to be undefined and the path to be defined */
|
||||
if (port || !path) { *p_status = VC_CONTAINER_ERROR_URI_OPEN_FAILED; goto error; }
|
||||
|
||||
if (!recognise_scheme(vc_uri_scheme(ctx->uri_parts)))
|
||||
{ *p_status = VC_CONTAINER_ERROR_URI_NOT_FOUND; goto error; }
|
||||
|
||||
stream = fopen(path, psz_mode);
|
||||
if(!stream) { *p_status = VC_CONTAINER_ERROR_URI_NOT_FOUND; goto error; }
|
||||
|
||||
*p_status = VC_CONTAINER_SUCCESS;
|
||||
return stream;
|
||||
|
||||
error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T write_byte_order(FILE *stream)
|
||||
{
|
||||
/* Simple byte order header word */
|
||||
uint32_t value = NATIVE_BYTE_ORDER;
|
||||
|
||||
if (fwrite(&value, 1, sizeof(value), stream) != sizeof(value))
|
||||
return VC_CONTAINER_ERROR_OUT_OF_SPACE;
|
||||
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T read_byte_order(FILE *stream, bool *is_native)
|
||||
{
|
||||
uint32_t value;
|
||||
|
||||
if (fread(&value, 1, sizeof(value), stream) != sizeof(value))
|
||||
return VC_CONTAINER_ERROR_EOS;
|
||||
|
||||
switch (value)
|
||||
{
|
||||
case NATIVE_BYTE_ORDER: *is_native = true; break;
|
||||
case SWAP_BYTE_ORDER: *is_native = false; break;
|
||||
default: return VC_CONTAINER_ERROR_CORRUPTED;
|
||||
}
|
||||
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_CONTAINER_STATUS_T vc_container_io_pktfile_open( VC_CONTAINER_IO_T *p_ctx,
|
||||
const char *unused, VC_CONTAINER_IO_MODE_T mode )
|
||||
{
|
||||
VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
|
||||
VC_CONTAINER_IO_MODULE_T *module = 0;
|
||||
FILE *stream = 0;
|
||||
bool is_native_order = true;
|
||||
VC_CONTAINER_PARAM_UNUSED(unused);
|
||||
|
||||
stream = open_file(p_ctx, mode, &status);
|
||||
if (status != VC_CONTAINER_SUCCESS) goto error;
|
||||
|
||||
if (mode == VC_CONTAINER_IO_MODE_WRITE)
|
||||
status = write_byte_order(stream);
|
||||
else
|
||||
status = read_byte_order(stream, &is_native_order);
|
||||
if (status != VC_CONTAINER_SUCCESS) goto error;
|
||||
|
||||
module = malloc( sizeof(*module) );
|
||||
if(!module) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
|
||||
memset(module, 0, sizeof(*module));
|
||||
|
||||
p_ctx->module = module;
|
||||
module->stream = stream;
|
||||
module->is_native_order = is_native_order;
|
||||
p_ctx->pf_close = io_pktfile_close;
|
||||
p_ctx->pf_read = io_pktfile_read;
|
||||
p_ctx->pf_write = io_pktfile_write;
|
||||
|
||||
/* Do not allow caching by I/O core, as this will merge packets in the cache. */
|
||||
p_ctx->capabilities = VC_CONTAINER_IO_CAPS_CANT_SEEK;
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
|
||||
error:
|
||||
if(stream) fclose(stream);
|
||||
return status;
|
||||
}
|
13
gfx/include/userland/containers/metadata/id3/CMakeLists.txt
Normal file
13
gfx/include/userland/containers/metadata/id3/CMakeLists.txt
Normal file
@ -0,0 +1,13 @@
|
||||
# Container module needs to go in as a plugins so different prefix
|
||||
# and install path
|
||||
set(CMAKE_SHARED_LIBRARY_PREFIX "")
|
||||
|
||||
# Make sure the compiler can find the necessary include files
|
||||
include_directories (../..)
|
||||
|
||||
add_library(reader_metadata_id3 ${LIBRARY_TYPE} id3_metadata_reader.c)
|
||||
|
||||
target_link_libraries(reader_metadata_id3 containers)
|
||||
|
||||
install(TARGETS reader_metadata_id3 DESTINATION ${VMCS_PLUGIN_DIR})
|
||||
|
@ -0,0 +1,450 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define CONTAINER_IS_BIG_ENDIAN
|
||||
//#define ENABLE_CONTAINERS_LOG_FORMAT
|
||||
//#define ENABLE_CONTAINERS_LOG_FORMAT_VERBOSE
|
||||
#define CONTAINER_HELPER_LOG_INDENT(a) 0
|
||||
#include "containers/core/containers_private.h"
|
||||
#include "containers/core/containers_io_helpers.h"
|
||||
#include "containers/core/containers_utils.h"
|
||||
#include "containers/core/containers_logging.h"
|
||||
|
||||
#include "id3_metadata_strings.h"
|
||||
|
||||
/******************************************************************************
|
||||
Defines
|
||||
******************************************************************************/
|
||||
#define ID3_SYNC_SAFE(x) ((((x >> 24) & 0x7f) << 21) | (((x >> 16) & 0x7f) << 14) | \
|
||||
(((x >> 8) & 0x7f) << 7) | (((x >> 0) & 0x7f) << 0))
|
||||
|
||||
/******************************************************************************
|
||||
Type definitions
|
||||
******************************************************************************/
|
||||
|
||||
/******************************************************************************
|
||||
Function prototypes
|
||||
******************************************************************************/
|
||||
VC_CONTAINER_STATUS_T id3_metadata_reader_open( VC_CONTAINER_T * );
|
||||
|
||||
/******************************************************************************
|
||||
Local Functions
|
||||
******************************************************************************/
|
||||
static VC_CONTAINER_METADATA_T *id3_metadata_append( VC_CONTAINER_T *p_ctx,
|
||||
VC_CONTAINER_METADATA_KEY_T key,
|
||||
unsigned int size )
|
||||
{
|
||||
VC_CONTAINER_METADATA_T *meta, **p_meta;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i != p_ctx->meta_num; ++i)
|
||||
{
|
||||
if (key == p_ctx->meta[i]->key) break;
|
||||
}
|
||||
|
||||
/* Avoid duplicate entries for now */
|
||||
if (i < p_ctx->meta_num) return NULL;
|
||||
|
||||
/* Sanity check size, truncate if necessary */
|
||||
size = MIN(size, 512);
|
||||
|
||||
/* Allocate a new metadata entry */
|
||||
if((meta = malloc(sizeof(VC_CONTAINER_METADATA_T) + size)) == NULL)
|
||||
return NULL;
|
||||
|
||||
/* We need to grow the array holding the metadata entries somehow, ideally,
|
||||
we'd like to use a linked structure of some sort but realloc is probably
|
||||
okay in this case */
|
||||
if((p_meta = realloc(p_ctx->meta, sizeof(VC_CONTAINER_METADATA_T *) * (p_ctx->meta_num + 1))) == NULL)
|
||||
{
|
||||
free(meta);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p_ctx->meta = p_meta;
|
||||
memset(meta, 0, sizeof(VC_CONTAINER_METADATA_T) + size);
|
||||
p_ctx->meta[p_ctx->meta_num] = meta;
|
||||
meta->key = key;
|
||||
meta->value = (char *)&meta[1];
|
||||
meta->size = size;
|
||||
p_ctx->meta_num++;
|
||||
|
||||
return meta;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_METADATA_T *id3_read_metadata_entry( VC_CONTAINER_T *p_ctx,
|
||||
VC_CONTAINER_METADATA_KEY_T key, unsigned int len )
|
||||
{
|
||||
VC_CONTAINER_METADATA_T *meta;
|
||||
|
||||
if ((meta = id3_metadata_append(p_ctx, key, len + 1)) != NULL)
|
||||
{
|
||||
unsigned int size = meta->size - 1;
|
||||
READ_BYTES(p_ctx, meta->value, size);
|
||||
|
||||
if (len > size)
|
||||
{
|
||||
LOG_DEBUG(p_ctx, "metadata value truncated (%d characters lost)", len - size);
|
||||
SKIP_BYTES(p_ctx, len - size);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SKIP_BYTES(p_ctx, len);
|
||||
}
|
||||
|
||||
return meta;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_METADATA_T *id3_read_metadata_entry_ex( VC_CONTAINER_T *p_ctx,
|
||||
VC_CONTAINER_METADATA_KEY_T key, unsigned int len, const char *encoding )
|
||||
{
|
||||
VC_CONTAINER_METADATA_T *meta;
|
||||
|
||||
if ((meta = id3_metadata_append(p_ctx, key, encoding ? len + 2 : len + 1)) != NULL)
|
||||
{
|
||||
unsigned int size;
|
||||
|
||||
if (encoding)
|
||||
{
|
||||
size = meta->size - 2;
|
||||
READ_STRING_UTF16(p_ctx, meta->value, size, "ID3v2 data");
|
||||
}
|
||||
else
|
||||
{
|
||||
size = meta->size - 1;
|
||||
READ_STRING(p_ctx, meta->value, size, "ID3v2 data");
|
||||
}
|
||||
|
||||
if (len > size)
|
||||
{
|
||||
LOG_DEBUG(p_ctx, "metadata value truncated (%d characters lost)", len - size);
|
||||
SKIP_BYTES(p_ctx, len - size);
|
||||
}
|
||||
}
|
||||
|
||||
return meta;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_METADATA_T *id3_add_metadata_entry( VC_CONTAINER_T *p_ctx,
|
||||
VC_CONTAINER_METADATA_KEY_T key, const char *value )
|
||||
{
|
||||
VC_CONTAINER_METADATA_T *meta;
|
||||
unsigned int len = strlen(value);
|
||||
|
||||
if ((meta = id3_metadata_append(p_ctx, key, len + 1)) != NULL)
|
||||
{
|
||||
unsigned int size = meta->size - 1;
|
||||
|
||||
if (len > size)
|
||||
{
|
||||
LOG_DEBUG(p_ctx, "metadata value truncated (%d characters lost)", len - size);
|
||||
}
|
||||
|
||||
strncpy(meta->value, value, size);
|
||||
}
|
||||
|
||||
return meta;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T id3_read_id3v2_frame( VC_CONTAINER_T *p_ctx,
|
||||
VC_CONTAINER_FOURCC_T frame_id, uint32_t frame_size )
|
||||
{
|
||||
VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
|
||||
VC_CONTAINER_METADATA_KEY_T key;
|
||||
VC_CONTAINER_METADATA_T *meta = NULL;
|
||||
uint8_t encoding;
|
||||
const char *charset = NULL;
|
||||
|
||||
if(frame_size < 1) return VC_CONTAINER_ERROR_CORRUPTED;
|
||||
|
||||
switch (frame_id)
|
||||
{
|
||||
case VC_FOURCC('T','A','L','B'): key = VC_CONTAINER_METADATA_KEY_ALBUM; break;
|
||||
case VC_FOURCC('T','I','T','2'): key = VC_CONTAINER_METADATA_KEY_TITLE; break;
|
||||
case VC_FOURCC('T','R','C','K'): key = VC_CONTAINER_METADATA_KEY_TRACK; break;
|
||||
case VC_FOURCC('T','P','E','1'): key = VC_CONTAINER_METADATA_KEY_ARTIST; break;
|
||||
case VC_FOURCC('T','C','O','N'): key = VC_CONTAINER_METADATA_KEY_GENRE; break;
|
||||
default: key = VC_CONTAINER_METADATA_KEY_UNKNOWN; break;
|
||||
}
|
||||
|
||||
if (key == VC_CONTAINER_METADATA_KEY_UNKNOWN) return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
|
||||
encoding = READ_U8(p_ctx, "ID3v2 text encoding byte");
|
||||
frame_size -= 1;
|
||||
|
||||
switch(encoding)
|
||||
{
|
||||
case 0: /* ISO-8859-1 */
|
||||
case 3: /* UTF-8 */
|
||||
break;
|
||||
case 1: /* UTF-16 with BOM */
|
||||
if(frame_size < 2) return VC_CONTAINER_ERROR_CORRUPTED;
|
||||
SKIP_U16(p_ctx, "ID3v2 text encoding BOM"); /* FIXME: Check BOM, 0xFFFE vs 0xFEFFF */
|
||||
frame_size -= 2;
|
||||
charset = "UTF16-LE";
|
||||
break;
|
||||
case 2: /* UTF-16BE */
|
||||
charset = "UTF16-BE";
|
||||
break;
|
||||
default:
|
||||
LOG_DEBUG(p_ctx, "skipping frame, text encoding %x not supported", encoding);
|
||||
SKIP_BYTES(p_ctx, frame_size);
|
||||
return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
if ((meta = id3_read_metadata_entry_ex(p_ctx, key, frame_size, charset)) != NULL)
|
||||
{
|
||||
if (charset)
|
||||
{
|
||||
utf8_from_charset(charset, meta->value, meta->size, meta->value, meta->size);
|
||||
}
|
||||
|
||||
meta->encoding = VC_CONTAINER_CHAR_ENCODING_UTF8; /* Okay for ISO-8859-1 as well? */
|
||||
|
||||
status = VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
SKIP_BYTES(p_ctx, frame_size);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T id3_read_id3v2_tag( VC_CONTAINER_T *p_ctx )
|
||||
{
|
||||
VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
|
||||
uint8_t maj_version, flags;
|
||||
uint32_t tag_size, size = 0;
|
||||
uint8_t peek_buf[10];
|
||||
|
||||
SKIP_STRING(p_ctx, 3, "ID3v2 identifier");
|
||||
maj_version = READ_U8(p_ctx, "ID3v2 version (major)");
|
||||
SKIP_U8(p_ctx, "ID3v2 version (minor)");
|
||||
flags = READ_U8(p_ctx, "ID3v2 flags");
|
||||
tag_size = READ_U32(p_ctx, "ID3v2 syncsafe tag size");
|
||||
tag_size = ID3_SYNC_SAFE(tag_size);
|
||||
LOG_DEBUG(p_ctx, "ID3v2 tag size: %d", tag_size);
|
||||
|
||||
/* Check that we support this major version */
|
||||
if (!(maj_version == 4 || maj_version == 3 || maj_version == 2))
|
||||
return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
|
||||
/* We can't currently handle unsynchronisation */
|
||||
if ((flags >> 7) & 1)
|
||||
{
|
||||
LOG_DEBUG(p_ctx, "skipping unsynchronised tag, not supported");
|
||||
return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
/* FIXME: check for version 2.2 and extract iTunes gapless playback information */
|
||||
if (maj_version == 2) return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
|
||||
if ((flags >> 6) & 1)
|
||||
{
|
||||
/* Skip extended header, we don't support it */
|
||||
uint32_t ext_hdr_size;
|
||||
LOG_DEBUG(p_ctx, "skipping ID3v2 extended header, not supported");
|
||||
ext_hdr_size = READ_U32(p_ctx, "ID3v2 syncsafe extended header size");
|
||||
ext_hdr_size = ID3_SYNC_SAFE(ext_hdr_size);
|
||||
LOG_DEBUG(p_ctx, "ID3v2 extended header size: %d", ext_hdr_size);
|
||||
SKIP_BYTES(p_ctx, MIN(tag_size, ext_hdr_size));
|
||||
size += ext_hdr_size;
|
||||
}
|
||||
|
||||
while (PEEK_BYTES(p_ctx, peek_buf, 10) == 10 && size < tag_size)
|
||||
{
|
||||
VC_CONTAINER_FOURCC_T frame_id;
|
||||
uint32_t frame_size;
|
||||
uint8_t format_flags;
|
||||
|
||||
frame_id = READ_FOURCC(p_ctx, "Frame ID");
|
||||
frame_size = READ_U32(p_ctx, "Frame Size");
|
||||
|
||||
if (maj_version >= 4)
|
||||
{
|
||||
frame_size = ID3_SYNC_SAFE(frame_size);
|
||||
LOG_DEBUG(p_ctx, "ID3v2 actual frame size: %d", frame_size);
|
||||
}
|
||||
|
||||
SKIP_U8(p_ctx, "ID3v2 status message flags");
|
||||
format_flags = READ_U8(p_ctx, "ID3v2 format description flags");
|
||||
|
||||
size += 10;
|
||||
|
||||
if((status = STREAM_STATUS(p_ctx)) != VC_CONTAINER_SUCCESS || !frame_id)
|
||||
break;
|
||||
|
||||
/* Early exit if we detect an invalid tag size */
|
||||
if (size + frame_size > tag_size)
|
||||
{
|
||||
status = VC_CONTAINER_ERROR_FORMAT_INVALID;
|
||||
break;
|
||||
}
|
||||
|
||||
/* We can't currently handle unsynchronised frames */
|
||||
if ((format_flags >> 1) & 1)
|
||||
{
|
||||
LOG_DEBUG(p_ctx, "skipping unsynchronised frame, not supported");
|
||||
SKIP_BYTES(p_ctx, frame_size);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((status = id3_read_id3v2_frame(p_ctx, frame_id, frame_size)) != VC_CONTAINER_SUCCESS)
|
||||
{
|
||||
LOG_DEBUG(p_ctx, "skipping unsupported frame");
|
||||
SKIP_BYTES(p_ctx, frame_size);
|
||||
}
|
||||
|
||||
size += frame_size;
|
||||
}
|
||||
|
||||
/* Try to skip to end of tag in case we bailed out early */
|
||||
if (size < tag_size) SKIP_BYTES(p_ctx, tag_size - size);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T id3_read_id3v1_tag( VC_CONTAINER_T *p_ctx )
|
||||
{
|
||||
VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
|
||||
uint8_t track, genre;
|
||||
char track_num[4] = {0};
|
||||
|
||||
SKIP_STRING(p_ctx, 3, "ID3v1 identifier");
|
||||
/* ID3v1 title */
|
||||
id3_read_metadata_entry(p_ctx, VC_CONTAINER_METADATA_KEY_TITLE, 30);
|
||||
/* ID3v1 artist */
|
||||
id3_read_metadata_entry(p_ctx, VC_CONTAINER_METADATA_KEY_ARTIST, 30);
|
||||
/* ID3v1 album */
|
||||
id3_read_metadata_entry(p_ctx, VC_CONTAINER_METADATA_KEY_ALBUM, 30);
|
||||
/* ID3v1 year */
|
||||
id3_read_metadata_entry(p_ctx, VC_CONTAINER_METADATA_KEY_YEAR, 4);
|
||||
SKIP_STRING(p_ctx, 28, "ID3v1 comment");
|
||||
if (READ_U8(p_ctx, "ID3v1 zero-byte") == 0)
|
||||
{
|
||||
track = READ_U8(p_ctx, "ID3v1 track");
|
||||
snprintf(track_num, sizeof(track_num) - 1, "%02d", track);
|
||||
id3_add_metadata_entry(p_ctx, VC_CONTAINER_METADATA_KEY_TRACK, track_num);
|
||||
}
|
||||
else
|
||||
{
|
||||
SKIP_BYTES(p_ctx, 1);
|
||||
}
|
||||
genre = READ_U8(p_ctx, "ID3v1 genre");
|
||||
if (genre < countof(id3_genres))
|
||||
{
|
||||
id3_add_metadata_entry(p_ctx, VC_CONTAINER_METADATA_KEY_GENRE, id3_genres[genre]);
|
||||
}
|
||||
|
||||
status = STREAM_STATUS(p_ctx);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
Functions exported as part of the Container Module API
|
||||
*****************************************************************************/
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T id3_metadata_reader_close( VC_CONTAINER_T *p_ctx )
|
||||
{
|
||||
VC_CONTAINER_PARAM_UNUSED(p_ctx);
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_CONTAINER_STATUS_T id3_metadata_reader_open( VC_CONTAINER_T *p_ctx )
|
||||
{
|
||||
VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_FORMAT_INVALID;
|
||||
uint8_t peek_buf[10];
|
||||
int64_t data_offset;
|
||||
|
||||
if (PEEK_BYTES(p_ctx, peek_buf, 10) != 10)
|
||||
return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
|
||||
/* Initial ID3v2 tag(s), variable size */
|
||||
while ((peek_buf[0] == 'I') && (peek_buf[1] == 'D') && (peek_buf[2] == '3'))
|
||||
{
|
||||
if ((status = id3_read_id3v2_tag(p_ctx)) != VC_CONTAINER_SUCCESS)
|
||||
{
|
||||
LOG_DEBUG(p_ctx, "error reading ID3v2 tag (%i)", status);
|
||||
}
|
||||
|
||||
if (PEEK_BYTES(p_ctx, peek_buf, 10) != 10) break;
|
||||
}
|
||||
|
||||
data_offset = STREAM_POSITION(p_ctx);
|
||||
|
||||
/* ID3v1 tag, 128 bytes at the end of a file */
|
||||
if (p_ctx->priv->io->size >= INT64_C(128) && STREAM_SEEKABLE(p_ctx))
|
||||
{
|
||||
SEEK(p_ctx, p_ctx->priv->io->size - INT64_C(128));
|
||||
if (PEEK_BYTES(p_ctx, peek_buf, 3) != 3) goto end;
|
||||
|
||||
if ((peek_buf[0] == 'T') && (peek_buf[1] == 'A') && (peek_buf[2] == 'G'))
|
||||
{
|
||||
if ((status = id3_read_id3v1_tag(p_ctx)) != VC_CONTAINER_SUCCESS)
|
||||
{
|
||||
LOG_DEBUG(p_ctx, "error reading ID3v1 tag (%i)", status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
/* Restore position to start of data */
|
||||
if (STREAM_POSITION(p_ctx) != data_offset)
|
||||
SEEK(p_ctx, data_offset);
|
||||
|
||||
p_ctx->priv->pf_close = id3_metadata_reader_close;
|
||||
|
||||
if((status = STREAM_STATUS(p_ctx)) != VC_CONTAINER_SUCCESS) goto error;
|
||||
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
|
||||
error:
|
||||
LOG_DEBUG(p_ctx, "error opening stream (%i)", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
/********************************************************************************
|
||||
Entrypoint function
|
||||
********************************************************************************/
|
||||
|
||||
#if !defined(ENABLE_CONTAINERS_STANDALONE) && defined(__HIGHC__)
|
||||
# pragma weak reader_open id3_metadata_reader_open
|
||||
#endif
|
@ -0,0 +1,179 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* ID3 genre byte translation table */
|
||||
static const char* id3_genres[] =
|
||||
{
|
||||
"Blues",
|
||||
"Classic Rock",
|
||||
"Country",
|
||||
"Dance",
|
||||
"Disco",
|
||||
"Funk",
|
||||
"Grunge",
|
||||
"Hip-Hop",
|
||||
"Jazz",
|
||||
"Metal",
|
||||
"New Age",
|
||||
"Oldies",
|
||||
"Other",
|
||||
"Pop",
|
||||
"R&B",
|
||||
"Rap",
|
||||
"Reggae",
|
||||
"Rock",
|
||||
"Techno",
|
||||
"Industrial",
|
||||
"Alternative",
|
||||
"Ska",
|
||||
"Death Metal",
|
||||
"Pranks",
|
||||
"Soundtrack",
|
||||
"Euro-Techno",
|
||||
"Ambient",
|
||||
"Trip-Hop",
|
||||
"Vocal",
|
||||
"Jazz+Funk",
|
||||
"Fusion",
|
||||
"Trance",
|
||||
"Classical",
|
||||
"Instrumental",
|
||||
"Acid",
|
||||
"House",
|
||||
"Game",
|
||||
"Sound Clip",
|
||||
"Gospel",
|
||||
"Noise",
|
||||
"Alternative Rock",
|
||||
"Bass",
|
||||
"Soul",
|
||||
"Punk",
|
||||
"Space",
|
||||
"Meditative",
|
||||
"Instrumental Pop",
|
||||
"Instrumental Rock",
|
||||
"Ethnic",
|
||||
"Gothic",
|
||||
"Darkwave",
|
||||
"Techno-Industrial",
|
||||
"Electronic",
|
||||
"Pop-Folk",
|
||||
"Eurodance",
|
||||
"Dream",
|
||||
"Southern Rock",
|
||||
"Comedy",
|
||||
"Cult",
|
||||
"Gangsta",
|
||||
"Top 40",
|
||||
"Christian Rap",
|
||||
"Pop/Funk",
|
||||
"Jungle",
|
||||
"Native American",
|
||||
"Cabaret",
|
||||
"New Wave",
|
||||
"Psychadelic",
|
||||
"Rave",
|
||||
"Showtunes",
|
||||
"Trailer",
|
||||
"Lo-Fi",
|
||||
"Tribal",
|
||||
"Acid Punk",
|
||||
"Acid Jazz",
|
||||
"Polka",
|
||||
"Retro",
|
||||
"Musical",
|
||||
"Rock & Roll",
|
||||
"Hard Rock",
|
||||
"Folk",
|
||||
"Folk-Rock",
|
||||
"National Folk",
|
||||
"Swing",
|
||||
"Fast Fusion",
|
||||
"Bebob",
|
||||
"Latin",
|
||||
"Revival",
|
||||
"Celtic",
|
||||
"Bluegrass",
|
||||
"Avantgarde",
|
||||
"Gothic Rock",
|
||||
"Progressive Rock",
|
||||
"Psychedelic Rock",
|
||||
"Symphonic Rock",
|
||||
"Slow Rock",
|
||||
"Big Band",
|
||||
"Chorus",
|
||||
"Easy Listening",
|
||||
"Acoustic",
|
||||
"Humour",
|
||||
"Speech",
|
||||
"Chanson",
|
||||
"Opera",
|
||||
"Chamber Music",
|
||||
"Sonata",
|
||||
"Symphony",
|
||||
"Booty Bass",
|
||||
"Primus",
|
||||
"Porn Groove",
|
||||
"Satire",
|
||||
"Slow Jam",
|
||||
"Club",
|
||||
"Tango",
|
||||
"Samba",
|
||||
"Folklore",
|
||||
"Ballad",
|
||||
"Power Ballad",
|
||||
"Rhythmic Soul",
|
||||
"Freestyle",
|
||||
"Duet",
|
||||
"Punk Rock",
|
||||
"Drum Solo",
|
||||
"A capella",
|
||||
"Euro-House",
|
||||
"Dance Hall",
|
||||
"Goa",
|
||||
"Drum & Bass",
|
||||
"Club-House",
|
||||
"Hardcore",
|
||||
"Terror",
|
||||
"Indie",
|
||||
"BritPop",
|
||||
"Negerpunk",
|
||||
"Polsk Punk",
|
||||
"Beat",
|
||||
"Christian Gangsta Rap",
|
||||
"Heavy Metal",
|
||||
"Black Metal",
|
||||
"Crossover",
|
||||
"Contemporary Christian",
|
||||
"Christian Rock",
|
||||
"Merengue",
|
||||
"Salsa",
|
||||
"Thrash Metal",
|
||||
"Anime",
|
||||
"JPop",
|
||||
"SynthPop"
|
||||
};
|
13
gfx/include/userland/containers/mkv/CMakeLists.txt
Normal file
13
gfx/include/userland/containers/mkv/CMakeLists.txt
Normal file
@ -0,0 +1,13 @@
|
||||
# Container module needs to go in as a plugins so different prefix
|
||||
# and install path
|
||||
set(CMAKE_SHARED_LIBRARY_PREFIX "")
|
||||
|
||||
# Make sure the compiler can find the necessary include files
|
||||
include_directories (../..)
|
||||
|
||||
add_library(reader_mkv ${LIBRARY_TYPE} matroska_reader.c)
|
||||
|
||||
target_link_libraries(reader_mkv containers)
|
||||
|
||||
install(TARGETS reader_mkv DESTINATION ${VMCS_PLUGIN_DIR})
|
||||
|
2323
gfx/include/userland/containers/mkv/matroska_reader.c
Normal file
2323
gfx/include/userland/containers/mkv/matroska_reader.c
Normal file
File diff suppressed because it is too large
Load Diff
19
gfx/include/userland/containers/mp4/CMakeLists.txt
Normal file
19
gfx/include/userland/containers/mp4/CMakeLists.txt
Normal file
@ -0,0 +1,19 @@
|
||||
# Container module needs to go in as a plugins so different prefix
|
||||
# and install path
|
||||
set(CMAKE_SHARED_LIBRARY_PREFIX "")
|
||||
|
||||
# Make sure the compiler can find the necessary include files
|
||||
include_directories (../..)
|
||||
|
||||
add_library(reader_mp4 ${LIBRARY_TYPE} mp4_reader.c)
|
||||
|
||||
target_link_libraries(reader_mp4 containers)
|
||||
|
||||
install(TARGETS reader_mp4 DESTINATION ${VMCS_PLUGIN_DIR})
|
||||
|
||||
add_library(writer_mp4 ${LIBRARY_TYPE} mp4_writer.c)
|
||||
|
||||
target_link_libraries(writer_mp4 containers)
|
||||
|
||||
install(TARGETS writer_mp4 DESTINATION ${VMCS_PLUGIN_DIR})
|
||||
|
128
gfx/include/userland/containers/mp4/mp4_common.h
Normal file
128
gfx/include/userland/containers/mp4/mp4_common.h
Normal file
@ -0,0 +1,128 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef MP4_COMMON_H
|
||||
#define MP4_COMMON_H
|
||||
|
||||
/******************************************************************************
|
||||
Type definitions.
|
||||
******************************************************************************/
|
||||
typedef enum {
|
||||
MP4_BOX_TYPE_UNKNOWN = 0,
|
||||
MP4_BOX_TYPE_ROOT = VC_FOURCC('r','o','o','t'),
|
||||
MP4_BOX_TYPE_FTYP = VC_FOURCC('f','t','y','p'),
|
||||
MP4_BOX_TYPE_MDAT = VC_FOURCC('m','d','a','t'),
|
||||
MP4_BOX_TYPE_MOOV = VC_FOURCC('m','o','o','v'),
|
||||
MP4_BOX_TYPE_MVHD = VC_FOURCC('m','v','h','d'),
|
||||
MP4_BOX_TYPE_TRAK = VC_FOURCC('t','r','a','k'),
|
||||
MP4_BOX_TYPE_TKHD = VC_FOURCC('t','k','h','d'),
|
||||
MP4_BOX_TYPE_MDIA = VC_FOURCC('m','d','i','a'),
|
||||
MP4_BOX_TYPE_MDHD = VC_FOURCC('m','d','h','d'),
|
||||
MP4_BOX_TYPE_HDLR = VC_FOURCC('h','d','l','r'),
|
||||
MP4_BOX_TYPE_MINF = VC_FOURCC('m','i','n','f'),
|
||||
MP4_BOX_TYPE_VMHD = VC_FOURCC('v','m','h','d'),
|
||||
MP4_BOX_TYPE_SMHD = VC_FOURCC('s','m','h','d'),
|
||||
MP4_BOX_TYPE_DINF = VC_FOURCC('d','i','n','f'),
|
||||
MP4_BOX_TYPE_DREF = VC_FOURCC('d','r','e','f'),
|
||||
MP4_BOX_TYPE_STBL = VC_FOURCC('s','t','b','l'),
|
||||
MP4_BOX_TYPE_STSD = VC_FOURCC('s','t','s','d'),
|
||||
MP4_BOX_TYPE_STTS = VC_FOURCC('s','t','t','s'),
|
||||
MP4_BOX_TYPE_CTTS = VC_FOURCC('c','t','t','s'),
|
||||
MP4_BOX_TYPE_STSC = VC_FOURCC('s','t','s','c'),
|
||||
MP4_BOX_TYPE_STSZ = VC_FOURCC('s','t','s','z'),
|
||||
MP4_BOX_TYPE_STCO = VC_FOURCC('s','t','c','o'),
|
||||
MP4_BOX_TYPE_CO64 = VC_FOURCC('c','o','6','4'),
|
||||
MP4_BOX_TYPE_STSS = VC_FOURCC('s','t','s','s'),
|
||||
MP4_BOX_TYPE_VIDE = VC_FOURCC('v','i','d','e'),
|
||||
MP4_BOX_TYPE_SOUN = VC_FOURCC('s','o','u','n'),
|
||||
MP4_BOX_TYPE_TEXT = VC_FOURCC('t','e','x','t'),
|
||||
MP4_BOX_TYPE_FREE = VC_FOURCC('f','r','e','e'),
|
||||
MP4_BOX_TYPE_SKIP = VC_FOURCC('s','k','i','p'),
|
||||
MP4_BOX_TYPE_WIDE = VC_FOURCC('w','i','d','e'),
|
||||
MP4_BOX_TYPE_PNOT = VC_FOURCC('p','m','o','t'),
|
||||
MP4_BOX_TYPE_PICT = VC_FOURCC('P','I','C','T'),
|
||||
MP4_BOX_TYPE_UDTA = VC_FOURCC('u','d','t','a'),
|
||||
MP4_BOX_TYPE_UUID = VC_FOURCC('u','u','i','d'),
|
||||
MP4_BOX_TYPE_ESDS = VC_FOURCC('e','s','d','s'),
|
||||
MP4_BOX_TYPE_AVCC = VC_FOURCC('a','v','c','C'),
|
||||
MP4_BOX_TYPE_D263 = VC_FOURCC('d','2','6','3'),
|
||||
MP4_BOX_TYPE_DAMR = VC_FOURCC('d','a','m','r'),
|
||||
MP4_BOX_TYPE_DAWP = VC_FOURCC('d','a','w','p'),
|
||||
MP4_BOX_TYPE_DEVC = VC_FOURCC('d','e','v','c'),
|
||||
MP4_BOX_TYPE_WAVE = VC_FOURCC('w','a','v','e'),
|
||||
MP4_BOX_TYPE_ZERO = 0
|
||||
} MP4_BOX_TYPE_T;
|
||||
|
||||
typedef enum {
|
||||
MP4_BRAND_ISOM = VC_FOURCC('i','s','o','m'),
|
||||
MP4_BRAND_MP42 = VC_FOURCC('m','p','4','2'),
|
||||
MP4_BRAND_3GP4 = VC_FOURCC('3','g','p','4'),
|
||||
MP4_BRAND_3GP5 = VC_FOURCC('3','g','p','5'),
|
||||
MP4_BRAND_3GP6 = VC_FOURCC('3','g','p','6'),
|
||||
MP4_BRAND_SKM2 = VC_FOURCC('s','k','m','2'),
|
||||
MP4_BRAND_SKM3 = VC_FOURCC('s','k','m','3'),
|
||||
MP4_BRAND_QT = VC_FOURCC('q','t',' ',' '),
|
||||
MP4_BRAND_NUM
|
||||
} MP4_BRAND_T;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MP4_SAMPLE_TABLE_STTS = 0, /* decoding time to sample */
|
||||
MP4_SAMPLE_TABLE_STSZ = 1, /* sample size */
|
||||
MP4_SAMPLE_TABLE_STSC = 2, /* sample to chunk */
|
||||
MP4_SAMPLE_TABLE_STCO = 3, /* sample to chunk-offset */
|
||||
MP4_SAMPLE_TABLE_STSS = 4, /* sync sample */
|
||||
MP4_SAMPLE_TABLE_CO64 = 5, /* sample to chunk-offset */
|
||||
MP4_SAMPLE_TABLE_CTTS = 6, /* composite time to sample */
|
||||
MP4_SAMPLE_TABLE_NUM
|
||||
} MP4_SAMPLE_TABLE_T;
|
||||
|
||||
/* Values for object_type_indication (mp4_decoder_config_descriptor)
|
||||
* see ISO/IEC 14496-1:2001(E) section 8.6.6.2 table 8 p. 30
|
||||
* see ISO/IEC 14496-15:2003 (draft) section 4.2.2 table 3 p. 11
|
||||
* see SKT Spec 8.2.3 p. 107
|
||||
* see 3GPP2 Spec v1.0 p. 22 */
|
||||
#define MP4_MPEG4_VISUAL_OBJECT_TYPE 0x20 /* visual ISO/IEC 14496-2 */
|
||||
#define MP4_MPEG4_H264_OBJECT_TYPE 0x21 /* visual ISO/IEC 14496-10 */
|
||||
#define MP4_MPEG4_H264_PS_OBJECT_TYPE 0x22 /* visual ISO/IEC 14496-10 (used for parameter ES) */
|
||||
#define MP4_MPEG4_AAC_LC_OBJECT_TYPE 0x40 /* audio ISO/IEC 14496-3 */
|
||||
#define MP4_MPEG2_SP_OBJECT_TYPE 0x60 /* visual ISO/IEC 13818-2 Simple Profile */
|
||||
#define MP4_MPEG2_MP_OBJECT_TYPE 0x61 /* visual ISO/IEC 13818-2 Main Profile */
|
||||
#define MP4_MPEG2_SNR_OBJECT_TYPE 0x62 /* visual ISO/IEC 13818-2 SNR Profile */
|
||||
#define MP4_MPEG2_AAC_LC_OBJECT_TYPE 0x67 /* audio ISO/IEC 13818-7 LowComplexity Profile */
|
||||
#define MP4_MP3_OBJECT_TYPE 0x69 /* audio ISO/IEC 13818-3 */
|
||||
#define MP4_MPEG1_VISUAL_OBJECT_TYPE 0x6A /* visual ISO/IEC 11172-2 */
|
||||
#define MP4_MPEG1_AUDIO_OBJECT_TYPE 0x6B /* audio ISO/IEC 11172-3 */
|
||||
#define MP4_JPEG_OBJECT_TYPE 0x6C /* visual ISO/IEC 10918-1 */
|
||||
#define MP4_SKT_EVRC_2V1_OBJECT_TYPE 0x82 /* SKT spec V2.1 for EVRC */
|
||||
#define MP4_KTF_EVRC_OBJECT_TYPE 0xC2 /* KTF spec V1.2 for EVRC */
|
||||
#define MP4_KTF_AMR_OBJECT_TYPE 0xC4 /* KTF spec V1.2 for AMR */
|
||||
#define MP4_KTF_MP3_OBJECT_TYPE 0xC5 /* KTF spec V1.2 for MP3 */
|
||||
#define MP4_SKT_TEXT_OBJECT_TYPE 0xD0 /* SKT spec V2.2 for Text */
|
||||
#define MP4_SKT_EVRC_OBJECT_TYPE 0xD1 /* SKT spec V2.2 for EVRC */
|
||||
#define MP4_3GPP2_QCELP_OBJECT_TYPE 0xE1 /* 3GPP2 spec V1.0 for QCELP13K */
|
||||
|
||||
#endif /* MP4_COMMON_H */
|
1879
gfx/include/userland/containers/mp4/mp4_reader.c
Normal file
1879
gfx/include/userland/containers/mp4/mp4_reader.c
Normal file
File diff suppressed because it is too large
Load Diff
1441
gfx/include/userland/containers/mp4/mp4_writer.c
Normal file
1441
gfx/include/userland/containers/mp4/mp4_writer.c
Normal file
File diff suppressed because it is too large
Load Diff
13
gfx/include/userland/containers/mpeg/CMakeLists.txt
Normal file
13
gfx/include/userland/containers/mpeg/CMakeLists.txt
Normal file
@ -0,0 +1,13 @@
|
||||
# Container module needs to go in as a plugins so different prefix
|
||||
# and install path
|
||||
set(CMAKE_SHARED_LIBRARY_PREFIX "")
|
||||
|
||||
# Make sure the compiler can find the necessary include files
|
||||
include_directories (../..)
|
||||
|
||||
add_library(reader_ps ${LIBRARY_TYPE} ps_reader.c)
|
||||
|
||||
target_link_libraries(reader_ps containers)
|
||||
|
||||
install(TARGETS reader_ps DESTINATION ${VMCS_PLUGIN_DIR})
|
||||
|
1268
gfx/include/userland/containers/mpeg/ps_reader.c
Normal file
1268
gfx/include/userland/containers/mpeg/ps_reader.c
Normal file
File diff suppressed because it is too large
Load Diff
13
gfx/include/userland/containers/mpga/CMakeLists.txt
Normal file
13
gfx/include/userland/containers/mpga/CMakeLists.txt
Normal file
@ -0,0 +1,13 @@
|
||||
# Container module needs to go in as a plugins so different prefix
|
||||
# and install path
|
||||
set(CMAKE_SHARED_LIBRARY_PREFIX "")
|
||||
|
||||
# Make sure the compiler can find the necessary include files
|
||||
include_directories (../..)
|
||||
|
||||
add_library(reader_mpga ${LIBRARY_TYPE} mpga_reader.c)
|
||||
|
||||
target_link_libraries(reader_mpga containers)
|
||||
|
||||
install(TARGETS reader_mpga DESTINATION ${VMCS_PLUGIN_DIR})
|
||||
|
147
gfx/include/userland/containers/mpga/mpga_common.h
Normal file
147
gfx/include/userland/containers/mpga/mpga_common.h
Normal file
@ -0,0 +1,147 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#define MPGA_HEADER_SIZE 6
|
||||
|
||||
#define MPGA_MODE_STEREO 0
|
||||
#define MPGA_MODE_JSTEREO 1
|
||||
#define MPGA_MODE_DUAL 2
|
||||
#define MPGA_MODE_MONO 3
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T mpga_read_header( uint8_t frame_header[MPGA_HEADER_SIZE],
|
||||
uint32_t *p_frame_size, unsigned int *p_frame_bitrate, unsigned int *p_version,
|
||||
unsigned int *p_layer, unsigned int *p_sample_rate, unsigned int *p_channels,
|
||||
unsigned int *p_frame_size_samples, unsigned int *p_offset )
|
||||
{
|
||||
static const uint16_t mpga_bitrate[2][3][15] =
|
||||
{{{0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448}, /* MPEG1, Layer 1 */
|
||||
{0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384}, /* MPEG1, Layer 2 */
|
||||
{0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320}},/* MPEG1, Layer 3 */
|
||||
{{0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256}, /* MPEG2 and MPEG2.5, Layer 1 */
|
||||
{0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160}, /* MPEG2 and MPEG2.5, Layer 2 */
|
||||
{0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160}} /* MPEG2 and MPEG2.5, Layer 3 */};
|
||||
static const uint16_t mpga_sample_rate[] = {44100, 48000, 32000};
|
||||
static const uint16_t mpga_frame_size[] = {384, 1152, 576};
|
||||
|
||||
unsigned int version, layer, br_id, sr_id, emphasis;
|
||||
unsigned int bitrate, sample_rate, padding, mode;
|
||||
|
||||
/* Check frame sync, 11 bits as we want to allow for MPEG2.5 */
|
||||
if (frame_header[0] != 0xff || (frame_header[1] & 0xe0) != 0xe0)
|
||||
return VC_CONTAINER_ERROR_FORMAT_INVALID;
|
||||
|
||||
version = 4 - ((frame_header[1] >> 3) & 3);
|
||||
layer = 4 - ((frame_header[1] >> 1) & 3 );
|
||||
br_id = (frame_header[2] >> 4) & 0xf;
|
||||
sr_id = (frame_header[2] >> 2) & 3;
|
||||
padding = (frame_header[2] >> 1) & 1;
|
||||
mode = (frame_header[3] >> 6) & 3;
|
||||
emphasis = (frame_header[3]) & 3;
|
||||
|
||||
/* Check for invalid values */
|
||||
if (version == 3 || layer == 4 || br_id == 15 || sr_id == 3 || emphasis == 2)
|
||||
return VC_CONTAINER_ERROR_FORMAT_INVALID;
|
||||
|
||||
if (version == 4) version = 3;
|
||||
|
||||
bitrate = mpga_bitrate[version == 1 ? 0 : 1][layer-1][br_id];
|
||||
bitrate *= 1000;
|
||||
|
||||
sample_rate = mpga_sample_rate[sr_id];
|
||||
sample_rate >>= (version - 1);
|
||||
|
||||
if (p_version) *p_version = version;
|
||||
if (p_layer) *p_layer = layer;
|
||||
if (p_sample_rate) *p_sample_rate = sample_rate;
|
||||
if (p_channels) *p_channels = mode == MPGA_MODE_MONO ? 1 : 2;
|
||||
if (p_frame_bitrate) *p_frame_bitrate = bitrate;
|
||||
if (p_offset) *p_offset = 0;
|
||||
|
||||
if (p_frame_size_samples)
|
||||
{
|
||||
*p_frame_size_samples = mpga_frame_size[layer - 1];
|
||||
if (version == 1 && layer == 3) *p_frame_size_samples <<= 1;
|
||||
}
|
||||
|
||||
if (!p_frame_size)
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
|
||||
if (!bitrate)
|
||||
*p_frame_size = 0;
|
||||
else if (layer == 1)
|
||||
*p_frame_size = (padding + bitrate * 12 / sample_rate) * 4;
|
||||
else if (layer == 2)
|
||||
*p_frame_size = padding + bitrate * 144 / sample_rate;
|
||||
else
|
||||
*p_frame_size = padding + bitrate * (version == 1 ? 144 : 72) / sample_rate;
|
||||
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T adts_read_header( uint8_t frame_header[MPGA_HEADER_SIZE],
|
||||
uint32_t *p_frame_size, unsigned int *p_frame_bitrate, unsigned int *p_version,
|
||||
unsigned int *p_layer, unsigned int *p_sample_rate, unsigned int *p_channels,
|
||||
unsigned int *p_frame_size_samples, unsigned int *p_offset )
|
||||
{
|
||||
static const unsigned int adts_sample_rate[16] =
|
||||
{96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350};
|
||||
unsigned int profile, sr_id, bitrate, sample_rate, frame_size, channels, crc;
|
||||
unsigned int frame_size_samples = 1024;
|
||||
|
||||
/* Check frame sync (12 bits) */
|
||||
if (frame_header[0] != 0xff || (frame_header[1] & 0xf0) != 0xf0)
|
||||
return VC_CONTAINER_ERROR_FORMAT_INVALID;
|
||||
|
||||
/* Layer must be 0 */
|
||||
if ((frame_header[1] >> 1) & 3)
|
||||
return VC_CONTAINER_ERROR_FORMAT_INVALID;
|
||||
|
||||
crc = !(frame_header[1] & 0x1);
|
||||
profile = (frame_header[2] >> 6) + 1; /* MPEG-4 Audio Object Type */
|
||||
|
||||
sr_id = (frame_header[2] >> 2) & 0xf;
|
||||
sample_rate = adts_sample_rate[sr_id];
|
||||
channels = ((frame_header[2] & 0x1) << 2) | ((frame_header[3] >> 6) & 0x3);
|
||||
frame_size = ((frame_header[3] & 0x03) << 11) | (frame_header[4] << 3) | (frame_header[5] >> 5);
|
||||
|
||||
if (!sample_rate || !channels || !frame_size)
|
||||
return VC_CONTAINER_ERROR_FORMAT_INVALID;
|
||||
|
||||
bitrate = frame_size * 8 * sample_rate / frame_size_samples;
|
||||
|
||||
if (p_version) *p_version = profile;
|
||||
if (p_layer) *p_layer = 0;
|
||||
if (p_sample_rate) *p_sample_rate = sample_rate;
|
||||
if (p_channels) *p_channels = channels;
|
||||
if (p_frame_bitrate) *p_frame_bitrate = bitrate;
|
||||
if (p_frame_size) *p_frame_size = frame_size;
|
||||
if (p_frame_size_samples) *p_frame_size_samples = frame_size_samples;
|
||||
if (p_offset) *p_offset = crc ? 9 : 7;
|
||||
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
288
gfx/include/userland/containers/mpga/mpga_packetizer.c
Normal file
288
gfx/include/userland/containers/mpga/mpga_packetizer.c
Normal file
@ -0,0 +1,288 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* Implementation of an MPEG1/2/2.5 audio Layer I/II/III and AAC ADTS packetizer.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "containers/packetizers.h"
|
||||
#include "containers/core/packetizers_private.h"
|
||||
#include "containers/core/containers_common.h"
|
||||
#include "containers/core/containers_logging.h"
|
||||
#include "containers/core/containers_time.h"
|
||||
#include "containers/core/containers_utils.h"
|
||||
#include "containers/core/containers_bytestream.h"
|
||||
#include "mpga_common.h"
|
||||
|
||||
#define MAX_FRAME_SIZE 2881 /* MPEG 2.5 Layer II, 8000 Hz, 160 kbps */
|
||||
|
||||
VC_CONTAINER_STATUS_T mpga_packetizer_open( VC_PACKETIZER_T * );
|
||||
|
||||
/*****************************************************************************/
|
||||
typedef struct VC_PACKETIZER_MODULE_T {
|
||||
enum {
|
||||
STATE_SYNC = 0,
|
||||
STATE_SYNC_LOST,
|
||||
STATE_SYNC_NEXT,
|
||||
STATE_SYNC_DONE,
|
||||
STATE_HEADER,
|
||||
STATE_DATA,
|
||||
} state;
|
||||
|
||||
VC_CONTAINER_STATUS_T (*pf_read_header)( uint8_t frame_header[MPGA_HEADER_SIZE],
|
||||
uint32_t *p_frame_size, unsigned int *p_frame_bitrate, unsigned int *p_version,
|
||||
unsigned int *p_layer, unsigned int *p_sample_rate, unsigned int *p_channels,
|
||||
unsigned int *p_frame_size_samples, unsigned int *p_offset);
|
||||
|
||||
uint32_t frame_size;
|
||||
unsigned int frame_bitrate;
|
||||
unsigned int version;
|
||||
unsigned int layer;
|
||||
unsigned int sample_rate;
|
||||
unsigned int channels;
|
||||
unsigned int frame_size_samples;
|
||||
unsigned int offset;
|
||||
|
||||
unsigned int lost_sync;
|
||||
|
||||
unsigned int stream_version;
|
||||
unsigned int stream_layer;
|
||||
|
||||
uint32_t bytes_read;
|
||||
|
||||
} VC_PACKETIZER_MODULE_T;
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T mpga_packetizer_close( VC_PACKETIZER_T *p_ctx )
|
||||
{
|
||||
free(p_ctx->priv->module);
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T mpga_packetizer_reset( VC_PACKETIZER_T *p_ctx )
|
||||
{
|
||||
VC_PACKETIZER_MODULE_T *module = p_ctx->priv->module;
|
||||
module->lost_sync = 0;
|
||||
module->state = STATE_SYNC;
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T mpga_packetizer_packetize( VC_PACKETIZER_T *p_ctx,
|
||||
VC_CONTAINER_PACKET_T *out, VC_PACKETIZER_FLAGS_T flags )
|
||||
{
|
||||
VC_PACKETIZER_MODULE_T *module = p_ctx->priv->module;
|
||||
VC_CONTAINER_BYTESTREAM_T *stream = &p_ctx->priv->stream;
|
||||
VC_CONTAINER_TIME_T *time = &p_ctx->priv->time;
|
||||
uint8_t header[MPGA_HEADER_SIZE];
|
||||
VC_CONTAINER_STATUS_T status;
|
||||
unsigned int version, layer;
|
||||
int64_t pts, dts;
|
||||
|
||||
while(1) switch (module->state)
|
||||
{
|
||||
case STATE_SYNC_LOST:
|
||||
bytestream_skip_byte( stream );
|
||||
if( !module->lost_sync++ )
|
||||
LOG_DEBUG(0, "lost sync");
|
||||
module->state = STATE_SYNC;
|
||||
|
||||
case STATE_SYNC:
|
||||
while( bytestream_peek( stream, header, 2 ) == VC_CONTAINER_SUCCESS )
|
||||
{
|
||||
/* 11 bits sync work (0xffe) */
|
||||
if( header[0] == 0xff && (header[1] & 0xe0) == 0xe0 )
|
||||
{
|
||||
module->state = STATE_HEADER;
|
||||
break;
|
||||
}
|
||||
bytestream_skip_byte( stream );
|
||||
module->lost_sync++;
|
||||
}
|
||||
if( module->state != STATE_HEADER )
|
||||
return VC_CONTAINER_ERROR_INCOMPLETE_DATA; /* We need more data */
|
||||
|
||||
case STATE_HEADER:
|
||||
if( bytestream_peek( stream, header, MPGA_HEADER_SIZE ) != VC_CONTAINER_SUCCESS )
|
||||
return VC_CONTAINER_ERROR_INCOMPLETE_DATA;
|
||||
|
||||
status = mpga_read_header( header,
|
||||
&module->frame_size, &module->frame_bitrate, &module->version,
|
||||
&module->layer, &module->sample_rate, &module->channels,
|
||||
&module->frame_size_samples, &module->offset );
|
||||
if (status != VC_CONTAINER_SUCCESS)
|
||||
{
|
||||
LOG_ERROR(0, "invalid header");
|
||||
module->state = STATE_SYNC_LOST;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Version and layer are not allowed to change mid-stream */
|
||||
if ((module->stream_version && module->stream_version != module->version) ||
|
||||
(module->stream_layer && module->stream_layer != module->layer))
|
||||
{
|
||||
LOG_ERROR(0, "invalid header");
|
||||
module->state = STATE_SYNC_LOST;
|
||||
break;
|
||||
}
|
||||
/* We currently do not support free format streams */
|
||||
if (!module->frame_size)
|
||||
{
|
||||
LOG_ERROR(0, "free format not supported");
|
||||
module->state = STATE_SYNC_LOST;
|
||||
break;
|
||||
}
|
||||
module->state = STATE_SYNC_NEXT;
|
||||
/* fall through to the next state */
|
||||
|
||||
case STATE_SYNC_NEXT:
|
||||
/* To avoid being caught by emulated start codes, we also look at where the next frame is supposed to be */
|
||||
if( bytestream_peek_at( stream, module->frame_size, header, MPGA_HEADER_SIZE ) != VC_CONTAINER_SUCCESS )
|
||||
{
|
||||
/* If we know there won't be anymore data then we can just assume
|
||||
* we've got the frame we're looking for */
|
||||
if (flags & VC_PACKETIZER_FLAG_FLUSH)
|
||||
{
|
||||
module->state = STATE_SYNC_DONE;
|
||||
break;
|
||||
}
|
||||
return VC_CONTAINER_ERROR_INCOMPLETE_DATA;
|
||||
}
|
||||
|
||||
status = mpga_read_header( header, 0, 0, &version, &layer, 0, 0, 0, 0 );
|
||||
if (status != VC_CONTAINER_SUCCESS)
|
||||
{
|
||||
LOG_ERROR(0, "invalid next header");
|
||||
module->state = STATE_SYNC_LOST;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Version and layer are not allowed to change mid-stream */
|
||||
if (module->version != version || module->layer != layer)
|
||||
{
|
||||
LOG_ERROR(0, "invalid header");
|
||||
module->state = STATE_SYNC_LOST;
|
||||
break;
|
||||
}
|
||||
|
||||
module->state = STATE_SYNC_DONE;
|
||||
/* fall through to the next state */
|
||||
|
||||
case STATE_SYNC_DONE:
|
||||
if( module->lost_sync )
|
||||
LOG_DEBUG(0, "recovered sync after %i bytes", module->lost_sync);
|
||||
module->lost_sync = 0;
|
||||
|
||||
bytestream_skip( stream, module->offset );
|
||||
module->stream_version = module->version;
|
||||
module->stream_layer = module->layer;
|
||||
|
||||
vc_container_time_set_samplerate(time, module->sample_rate, 1);
|
||||
bytestream_get_timestamps(stream, &pts, &dts, true);
|
||||
|
||||
vc_container_time_set(time, pts);
|
||||
|
||||
module->bytes_read = 0;
|
||||
module->state = STATE_DATA;
|
||||
/* fall through to the next state */
|
||||
|
||||
case STATE_DATA:
|
||||
if( bytestream_size( stream ) < module->frame_size)
|
||||
return VC_CONTAINER_ERROR_INCOMPLETE_DATA;
|
||||
|
||||
out->size = module->frame_size - module->bytes_read;
|
||||
out->pts = out->dts = VC_CONTAINER_TIME_UNKNOWN;
|
||||
out->flags = VC_CONTAINER_PACKET_FLAG_FRAME_END;
|
||||
|
||||
if(!module->bytes_read)
|
||||
{
|
||||
out->pts = out->dts = vc_container_time_get(time);
|
||||
out->flags |= VC_CONTAINER_PACKET_FLAG_FRAME_START;
|
||||
}
|
||||
|
||||
if(flags & VC_PACKETIZER_FLAG_INFO)
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
|
||||
if(flags & VC_PACKETIZER_FLAG_SKIP)
|
||||
{
|
||||
bytestream_skip( stream, out->size );
|
||||
}
|
||||
else
|
||||
{
|
||||
out->size = MIN(out->size, out->buffer_size);
|
||||
bytestream_get( stream, out->data, out->size );
|
||||
}
|
||||
module->bytes_read += out->size;
|
||||
|
||||
if(module->bytes_read == module->frame_size)
|
||||
{
|
||||
vc_container_time_add(time, module->frame_size_samples);
|
||||
module->state = STATE_HEADER;
|
||||
}
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
|
||||
default:
|
||||
break;
|
||||
};
|
||||
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_CONTAINER_STATUS_T mpga_packetizer_open( VC_PACKETIZER_T *p_ctx )
|
||||
{
|
||||
VC_PACKETIZER_MODULE_T *module;
|
||||
|
||||
if(p_ctx->in->codec != VC_CONTAINER_CODEC_MPGA &&
|
||||
p_ctx->in->codec != VC_CONTAINER_CODEC_MP4A)
|
||||
return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
|
||||
p_ctx->priv->module = module = malloc(sizeof(*module));
|
||||
if(!module)
|
||||
return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
|
||||
memset(module, 0, sizeof(*module));
|
||||
|
||||
if(p_ctx->in->codec == VC_CONTAINER_CODEC_MPGA)
|
||||
module->pf_read_header = mpga_read_header;
|
||||
else
|
||||
module->pf_read_header = adts_read_header;
|
||||
|
||||
vc_container_format_copy( p_ctx->out, p_ctx->in, 0);
|
||||
p_ctx->max_frame_size = MAX_FRAME_SIZE;
|
||||
p_ctx->priv->pf_close = mpga_packetizer_close;
|
||||
p_ctx->priv->pf_packetize = mpga_packetizer_packetize;
|
||||
p_ctx->priv->pf_reset = mpga_packetizer_reset;
|
||||
LOG_DEBUG(0, "using mpeg audio packetizer");
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_PACKETIZER_REGISTER(mpga_packetizer_open, "mpga");
|
618
gfx/include/userland/containers/mpga/mpga_reader.c
Normal file
618
gfx/include/userland/containers/mpga/mpga_reader.c
Normal file
@ -0,0 +1,618 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define CONTAINER_IS_BIG_ENDIAN
|
||||
//#define ENABLE_CONTAINERS_LOG_FORMAT
|
||||
//#define ENABLE_CONTAINERS_LOG_FORMAT_VERBOSE
|
||||
#define CONTAINER_HELPER_LOG_INDENT(a) 0
|
||||
#include "containers/core/containers_private.h"
|
||||
#include "containers/core/containers_io_helpers.h"
|
||||
#include "containers/core/containers_utils.h"
|
||||
#include "containers/core/containers_logging.h"
|
||||
#include "mpga_common.h"
|
||||
|
||||
/******************************************************************************
|
||||
Defines and constants.
|
||||
******************************************************************************/
|
||||
#define MPGA_XING_HAS_FRAMES 0x00000001
|
||||
#define MPGA_XING_HAS_BYTES 0x00000002
|
||||
#define MPGA_XING_HAS_TOC 0x00000004
|
||||
#define MPGA_XING_HAS_QUALITY 0x00000008
|
||||
|
||||
#define MPGA_MAX_BAD_FRAMES 4096 /*< Maximum number of failed byte-wise syncs,
|
||||
should be at least 2881+4 to cover the largest
|
||||
frame size (MPEG2.5 Layer 2, 160kbit/s 8kHz)
|
||||
+ next frame header */
|
||||
|
||||
static const unsigned int mpga_sample_rate_adts[16] =
|
||||
{96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350};
|
||||
|
||||
static const GUID_T asf_guid_header =
|
||||
{0x75B22630, 0x668E, 0x11CF, {0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C}};
|
||||
|
||||
/******************************************************************************
|
||||
Type definitions
|
||||
******************************************************************************/
|
||||
typedef struct VC_CONTAINER_MODULE_T
|
||||
{
|
||||
VC_CONTAINER_TRACK_T *track;
|
||||
uint64_t data_offset;
|
||||
uint64_t data_size;
|
||||
uint64_t num_frames; /**< Total number of frames (if known) */
|
||||
unsigned int frame_size_samples; /**< Frame size in samples */
|
||||
unsigned int bitrate; /**< Bitrate (might change on a per-frame basis if VBR) */
|
||||
unsigned int sample_rate;
|
||||
unsigned int channels;
|
||||
|
||||
/* MPEG audio header information */
|
||||
unsigned int version; /**< 1 for MPEG1, 2 for MPEG2, etc. */
|
||||
unsigned int layer;
|
||||
|
||||
/* VBR header information */
|
||||
uint8_t xing_toc[100];
|
||||
int xing_toc_valid;
|
||||
|
||||
/* Per-frame state (updated upon a read or a seek) */
|
||||
unsigned int frame_size;
|
||||
unsigned int frame_data_left;
|
||||
uint64_t frame_index;
|
||||
int64_t frame_offset;
|
||||
int64_t frame_time_pos; /**< pts of current frame */
|
||||
unsigned int frame_bitrate; /**< bitrate of current frame */
|
||||
|
||||
VC_CONTAINER_STATUS_T (*pf_parse_header)( uint8_t frame_header[MPGA_HEADER_SIZE],
|
||||
uint32_t *p_frame_size, unsigned int *p_frame_bitrate, unsigned int *p_version,
|
||||
unsigned int *p_layer, unsigned int *p_sample_rate, unsigned int *p_channels,
|
||||
unsigned int *p_frame_size_samples, unsigned int *p_offset);
|
||||
|
||||
uint8_t extradata[2]; /**< codec extra data for aac */
|
||||
|
||||
} VC_CONTAINER_MODULE_T;
|
||||
|
||||
/******************************************************************************
|
||||
Function prototypes
|
||||
******************************************************************************/
|
||||
VC_CONTAINER_STATUS_T mpga_reader_open( VC_CONTAINER_T * );
|
||||
|
||||
/******************************************************************************
|
||||
Local Functions
|
||||
******************************************************************************/
|
||||
static uint32_t PEEK_BYTES_AT( VC_CONTAINER_T *p_ctx, int64_t offset, uint8_t *buffer, int size )
|
||||
{
|
||||
int ret;
|
||||
int64_t current_position = STREAM_POSITION(p_ctx);
|
||||
SEEK(p_ctx, current_position + offset);
|
||||
ret = PEEK_BYTES(p_ctx, buffer, size);
|
||||
SEEK(p_ctx, current_position);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T mpga_check_frame_header( VC_CONTAINER_T *p_ctx,
|
||||
VC_CONTAINER_MODULE_T *module, uint8_t frame_header[MPGA_HEADER_SIZE] )
|
||||
{
|
||||
VC_CONTAINER_PARAM_UNUSED(p_ctx);
|
||||
return module->pf_parse_header(frame_header, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T mpga_sync( VC_CONTAINER_T *p_ctx )
|
||||
{
|
||||
VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
|
||||
VC_CONTAINER_STATUS_T status;
|
||||
uint8_t frame_header[MPGA_HEADER_SIZE];
|
||||
uint32_t frame_size;
|
||||
unsigned int frame_bitrate, version, layer, sample_rate, channels;
|
||||
unsigned int frame_size_samples, offset;
|
||||
int sync_count = 0;
|
||||
|
||||
/* If we can't see a full frame header, we treat this as EOS although it
|
||||
could be a bad stream as well, the caller should distinct between
|
||||
these two cases */
|
||||
if (PEEK_BYTES(p_ctx, (uint8_t*)frame_header, MPGA_HEADER_SIZE) != MPGA_HEADER_SIZE)
|
||||
return VC_CONTAINER_ERROR_EOS;
|
||||
|
||||
while (sync_count++ < MPGA_MAX_BAD_FRAMES)
|
||||
{
|
||||
status = module->pf_parse_header(frame_header, &frame_size, &frame_bitrate,
|
||||
&version, &layer, &sample_rate, &channels,
|
||||
&frame_size_samples, &offset);
|
||||
if (status == VC_CONTAINER_SUCCESS &&
|
||||
frame_size /* We do not support free format streams */)
|
||||
{
|
||||
LOG_DEBUG(p_ctx, "MPEGv%d, layer %d, %d bps, %d Hz",
|
||||
version, layer, frame_bitrate, sample_rate);
|
||||
if (PEEK_BYTES_AT(p_ctx, (int64_t)frame_size, frame_header, MPGA_HEADER_SIZE) != MPGA_HEADER_SIZE ||
|
||||
mpga_check_frame_header(p_ctx, module, frame_header) == VC_CONTAINER_SUCCESS)
|
||||
break;
|
||||
|
||||
/* If we've reached an ID3 tag then the frame is valid as well */
|
||||
if((frame_header[0] == 'I' && frame_header[1] == 'D' && frame_header[2] == '3') ||
|
||||
(frame_header[0] == 'T' && frame_header[1] == 'A' && frame_header[2] == 'G'))
|
||||
break;
|
||||
}
|
||||
else if (status == VC_CONTAINER_SUCCESS)
|
||||
{
|
||||
LOG_DEBUG(p_ctx, "free format not supported");
|
||||
}
|
||||
|
||||
if (SKIP_BYTES(p_ctx, 1) != 1 || PEEK_BYTES(p_ctx, (uint8_t*)frame_header, MPGA_HEADER_SIZE) != MPGA_HEADER_SIZE)
|
||||
return VC_CONTAINER_ERROR_EOS;
|
||||
}
|
||||
|
||||
if(sync_count > MPGA_MAX_BAD_FRAMES) /* We didn't find a valid frame */
|
||||
return VC_CONTAINER_ERROR_FORMAT_INVALID;
|
||||
|
||||
if (module->version)
|
||||
{
|
||||
/* FIXME: we don't currently care whether or not the number of channels changes mid-stream */
|
||||
if (version != module->version || layer != module->layer)
|
||||
{
|
||||
LOG_DEBUG(p_ctx, "version or layer not allowed to change mid-stream");
|
||||
return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
module->version = version;
|
||||
module->layer = layer;
|
||||
module->sample_rate = sample_rate;
|
||||
module->channels = channels;
|
||||
module->frame_size_samples = frame_size_samples;
|
||||
}
|
||||
|
||||
if(offset) SKIP_BYTES(p_ctx, offset);
|
||||
module->frame_data_left = module->frame_size = frame_size - offset;
|
||||
module->frame_bitrate = frame_bitrate;
|
||||
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static int64_t mpga_calculate_frame_time( VC_CONTAINER_T *p_ctx )
|
||||
{
|
||||
VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
|
||||
int64_t time;
|
||||
time = INT64_C(1000000) * module->frame_index *
|
||||
module->frame_size_samples / module->sample_rate;
|
||||
return time;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T mpga_read_vbr_headers( VC_CONTAINER_T *p_ctx )
|
||||
{
|
||||
VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
|
||||
VC_CONTAINER_TRACK_T *track = p_ctx->tracks[0];
|
||||
VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_NOT_FOUND;
|
||||
uint32_t peek_buf[1];
|
||||
int64_t offset, start = STREAM_POSITION(p_ctx);
|
||||
|
||||
/* Look for XING header (immediately after layer 3 side information) */
|
||||
offset = (module->version == 1) ? ((module->channels == 1) ? INT64_C(21) : INT64_C(36)) :
|
||||
((module->channels == 1) ? INT64_C(13) : INT64_C(21));
|
||||
|
||||
if (PEEK_BYTES_AT(p_ctx, offset, (uint8_t*)peek_buf, 4) != 4)
|
||||
return VC_CONTAINER_ERROR_FORMAT_INVALID; /* File would be way too small */
|
||||
|
||||
if (peek_buf[0] == VC_FOURCC('X','i','n','g') || peek_buf[0] == VC_FOURCC('I','n','f','o'))
|
||||
{
|
||||
uint32_t flags = 0, num_frames = 0, data_size = 0;
|
||||
|
||||
/* If the first frame has a XING header then we know it's a valid (but empty) audio
|
||||
frame so we safely parse the header whilst skipping to the next frame */
|
||||
SKIP_BYTES(p_ctx, offset); /* FIXME: we don't care about layer 3 side information? */
|
||||
|
||||
SKIP_FOURCC(p_ctx, "XING");
|
||||
flags = READ_U32(p_ctx, "XING flags");
|
||||
|
||||
if (flags & MPGA_XING_HAS_FRAMES)
|
||||
num_frames = READ_U32(p_ctx, "XING frames");
|
||||
|
||||
if (flags & MPGA_XING_HAS_BYTES)
|
||||
data_size = READ_U32(p_ctx, "XING bytes");
|
||||
|
||||
if (flags & MPGA_XING_HAS_TOC)
|
||||
{
|
||||
READ_BYTES(p_ctx, module->xing_toc, sizeof(module->xing_toc));
|
||||
/* TOC is useful only if we know the number of frames */
|
||||
if (num_frames) module->xing_toc_valid = 1;
|
||||
/* Ensure time zero points to first frame even if TOC is broken */
|
||||
module->xing_toc[0] = 0;
|
||||
}
|
||||
|
||||
if (flags & MPGA_XING_HAS_QUALITY)
|
||||
SKIP_U32(p_ctx, "XING quality");
|
||||
|
||||
module->data_size = data_size;
|
||||
module->num_frames = num_frames;
|
||||
|
||||
if (module->num_frames && module->data_size)
|
||||
{
|
||||
/* We can calculate average bitrate */
|
||||
module->bitrate =
|
||||
module->data_size * module->sample_rate * 8 / (module->num_frames * module->frame_size_samples);
|
||||
}
|
||||
|
||||
p_ctx->duration = (module->num_frames * module->frame_size_samples * 1000000LL) / module->sample_rate;
|
||||
|
||||
/* Look for additional LAME header (follows XING) */
|
||||
if (PEEK_BYTES(p_ctx, (uint8_t*)peek_buf, 4) != 4)
|
||||
return VC_CONTAINER_ERROR_FORMAT_INVALID; /* File would still be way too small */
|
||||
|
||||
if (peek_buf[0] == VC_FOURCC('L','A','M','E'))
|
||||
{
|
||||
uint32_t encoder_delay;
|
||||
|
||||
SKIP_FOURCC(p_ctx, "LAME");
|
||||
SKIP_STRING(p_ctx, 5, "LAME encoder version");
|
||||
SKIP_U8(p_ctx, "LAME tag revision/VBR method");
|
||||
SKIP_U8(p_ctx, "LAME LP filter value");
|
||||
SKIP_U32(p_ctx, "LAME peak signal amplitude");
|
||||
SKIP_U16(p_ctx, "LAME radio replay gain");
|
||||
SKIP_U16(p_ctx, "LAME audiophile replay gain");
|
||||
SKIP_U8(p_ctx, "LAME encoder flags");
|
||||
SKIP_U8(p_ctx, "LAME ABR/minimal bitrate");
|
||||
encoder_delay = READ_U24(p_ctx, "LAME encoder delay/padding");
|
||||
SKIP_U8(p_ctx, "LAME misc");
|
||||
SKIP_U8(p_ctx, "LAME MP3 gain");
|
||||
SKIP_U16(p_ctx, "LAME presets and surround info");
|
||||
SKIP_U32(p_ctx, "LAME music length");
|
||||
SKIP_U16(p_ctx, "LAME music CRC");
|
||||
SKIP_U16(p_ctx, "LAME tag CRC");
|
||||
track->format->type->audio.gap_delay = (encoder_delay >> 12) + module->frame_size_samples;
|
||||
track->format->type->audio.gap_padding = encoder_delay & 0xfff;
|
||||
}
|
||||
|
||||
SEEK(p_ctx, start);
|
||||
status = VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/* FIXME: if not success, try to read 'VBRI' header */
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
Functions exported as part of the Container Module API
|
||||
*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T mpga_reader_read( VC_CONTAINER_T *p_ctx,
|
||||
VC_CONTAINER_PACKET_T *p_packet, uint32_t flags )
|
||||
{
|
||||
VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
|
||||
VC_CONTAINER_TRACK_T *track = p_ctx->tracks[0];
|
||||
VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
|
||||
|
||||
if (module->frame_data_left == 0)
|
||||
{
|
||||
status = mpga_sync(p_ctx);
|
||||
if (status != VC_CONTAINER_SUCCESS) goto error;
|
||||
}
|
||||
|
||||
if (module->bitrate)
|
||||
{
|
||||
/* Simple moving average over bitrate values seen so far */
|
||||
module->bitrate = (module->bitrate * 31 + module->frame_bitrate) >> 5;
|
||||
}
|
||||
else
|
||||
{
|
||||
module->bitrate = module->frame_bitrate;
|
||||
}
|
||||
|
||||
/* Check if we can skip the frame straight-away */
|
||||
if (!track->is_enabled ||
|
||||
((flags & VC_CONTAINER_READ_FLAG_SKIP) && !(flags & VC_CONTAINER_READ_FLAG_INFO)))
|
||||
{
|
||||
/* Just skip the frame */
|
||||
SKIP_BYTES(p_ctx, module->frame_size);
|
||||
module->frame_data_left = 0;
|
||||
if(!track->is_enabled)
|
||||
status = VC_CONTAINER_ERROR_CONTINUE;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Fill in packet information */
|
||||
p_packet->flags = p_packet->track = 0;
|
||||
if (module->frame_data_left == module->frame_size)
|
||||
p_packet->flags |= VC_CONTAINER_PACKET_FLAG_FRAME;
|
||||
else
|
||||
p_packet->flags |= VC_CONTAINER_PACKET_FLAG_FRAME_END;
|
||||
|
||||
p_packet->size = module->frame_data_left;
|
||||
|
||||
p_packet->pts = module->frame_time_pos;
|
||||
p_packet->dts = VC_CONTAINER_TIME_UNKNOWN;
|
||||
|
||||
if ((flags & VC_CONTAINER_READ_FLAG_SKIP))
|
||||
{
|
||||
SKIP_BYTES(p_ctx, module->frame_size);
|
||||
module->frame_data_left = 0;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (flags & VC_CONTAINER_READ_FLAG_INFO)
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
|
||||
p_packet->size = MIN(p_packet->buffer_size, module->frame_data_left);
|
||||
p_packet->size = READ_BYTES(p_ctx, p_packet->data, p_packet->size);
|
||||
module->frame_data_left -= p_packet->size;
|
||||
|
||||
end:
|
||||
if (module->frame_data_left == 0)
|
||||
{
|
||||
module->frame_index++;
|
||||
module->frame_offset += module->frame_size;
|
||||
module->frame_time_pos = mpga_calculate_frame_time(p_ctx);
|
||||
|
||||
#if 0 /* FIXME: is this useful e.g. progressive download? */
|
||||
module->num_frames = MAX(module->num_frames, module->frame_index);
|
||||
module->data_size = MAX(module->data_size, module->frame_offset);
|
||||
p_ctx->duration = MAX(p_ctx->duration, mpga_calculate_frame_time(p_ctx));
|
||||
#endif
|
||||
}
|
||||
|
||||
return status == VC_CONTAINER_SUCCESS ? STREAM_STATUS(p_ctx) : status;
|
||||
|
||||
error:
|
||||
return status;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T mpga_reader_seek( VC_CONTAINER_T *p_ctx,
|
||||
int64_t *p_offset,
|
||||
VC_CONTAINER_SEEK_MODE_T mode,
|
||||
VC_CONTAINER_SEEK_FLAGS_T flags)
|
||||
{
|
||||
VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
|
||||
VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
|
||||
uint64_t seekpos, position = STREAM_POSITION(p_ctx);
|
||||
VC_CONTAINER_PARAM_UNUSED(flags);
|
||||
|
||||
if (mode != VC_CONTAINER_SEEK_MODE_TIME || !STREAM_SEEKABLE(p_ctx))
|
||||
return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
|
||||
|
||||
if (*p_offset != INT64_C(0))
|
||||
{
|
||||
if (!p_ctx->duration)
|
||||
return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
|
||||
|
||||
if (module->xing_toc_valid)
|
||||
{
|
||||
int64_t ppm;
|
||||
int percent, lower, upper, delta;
|
||||
|
||||
ppm = (*p_offset * module->sample_rate) / (module->num_frames * module->frame_size_samples);
|
||||
ppm = MIN(ppm, INT64_C(999999));
|
||||
|
||||
percent = ppm / 10000;
|
||||
delta = ppm % 10000;
|
||||
|
||||
lower = module->xing_toc[percent];
|
||||
upper = percent < 99 ? module->xing_toc[percent + 1] : 256;
|
||||
|
||||
seekpos = module->data_offset +
|
||||
(((module->data_size * lower) + (module->data_size * (upper - lower) * delta) / 10000) >> 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The following will be accurate for CBR only */
|
||||
seekpos = module->data_offset + (*p_offset * module->data_size) / p_ctx->duration;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
seekpos = module->data_offset;
|
||||
}
|
||||
|
||||
SEEK(p_ctx, seekpos);
|
||||
status = mpga_sync(p_ctx);
|
||||
if (status && status != VC_CONTAINER_ERROR_EOS)
|
||||
goto error;
|
||||
|
||||
module->frame_index = (*p_offset * module->num_frames + (p_ctx->duration >> 1)) / p_ctx->duration;
|
||||
module->frame_offset = STREAM_POSITION(p_ctx) - module->data_offset;
|
||||
|
||||
*p_offset = module->frame_time_pos = mpga_calculate_frame_time(p_ctx);
|
||||
|
||||
return STREAM_STATUS(p_ctx);
|
||||
|
||||
error:
|
||||
SEEK(p_ctx, position);
|
||||
return status;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T mpga_reader_close( VC_CONTAINER_T *p_ctx )
|
||||
{
|
||||
VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
|
||||
|
||||
if (p_ctx->tracks_num != 0)
|
||||
vc_container_free_track(p_ctx, p_ctx->tracks[0]);
|
||||
p_ctx->tracks = NULL;
|
||||
p_ctx->tracks_num = 0;
|
||||
free(module);
|
||||
p_ctx->priv->module = 0;
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_CONTAINER_STATUS_T mpga_reader_open( VC_CONTAINER_T *p_ctx )
|
||||
{
|
||||
const char *extension = vc_uri_path_extension(p_ctx->priv->uri);
|
||||
VC_CONTAINER_MODULE_T *module = 0;
|
||||
VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
|
||||
VC_CONTAINER_TRACK_T *track = NULL;
|
||||
unsigned int i;
|
||||
GUID_T guid;
|
||||
|
||||
/* Check if the user has specified a container */
|
||||
vc_uri_find_query(p_ctx->priv->uri, 0, "container", &extension);
|
||||
|
||||
/* Since mpeg audio is difficult to auto-detect, we use the extension as
|
||||
part of the autodetection */
|
||||
if(!extension)
|
||||
return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
if(strcasecmp(extension, "mp3") && strcasecmp(extension, "mp2") &&
|
||||
strcasecmp(extension, "aac") && strcasecmp(extension, "adts"))
|
||||
return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
|
||||
/* Check we're not in fact dealing with an ASF file */
|
||||
if(PEEK_BYTES(p_ctx, (uint8_t *)&guid, sizeof(guid)) == sizeof(guid) &&
|
||||
!memcmp(&guid, &asf_guid_header, sizeof(guid)))
|
||||
return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
|
||||
LOG_DEBUG(p_ctx, "using mpga reader");
|
||||
|
||||
/* Allocate our context */
|
||||
if ((module = malloc(sizeof(*module))) == NULL)
|
||||
{
|
||||
status = VC_CONTAINER_ERROR_OUT_OF_MEMORY;
|
||||
goto error;
|
||||
}
|
||||
|
||||
memset(module, 0, sizeof(*module));
|
||||
p_ctx->priv->module = module;
|
||||
p_ctx->tracks = &module->track;
|
||||
|
||||
p_ctx->tracks[0] = vc_container_allocate_track(p_ctx, 0);
|
||||
if(!p_ctx->tracks[0])
|
||||
{
|
||||
status = VC_CONTAINER_ERROR_OUT_OF_MEMORY;
|
||||
goto error;
|
||||
}
|
||||
p_ctx->tracks_num = 1;
|
||||
|
||||
module->pf_parse_header = mpga_read_header;
|
||||
if(!strcasecmp(extension, "aac") || !strcasecmp(extension, "adts"))
|
||||
module->pf_parse_header = adts_read_header;
|
||||
|
||||
if ((status = mpga_sync(p_ctx)) != VC_CONTAINER_SUCCESS)
|
||||
{
|
||||
/* An error here probably means it's not an mpga file at all */
|
||||
if(status == VC_CONTAINER_ERROR_FORMAT_INVALID)
|
||||
status = VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* If we got this far, we're probably dealing with an mpeg audio file */
|
||||
track = p_ctx->tracks[0];
|
||||
track->format->es_type = VC_CONTAINER_ES_TYPE_AUDIO;
|
||||
track->format->codec = VC_CONTAINER_CODEC_MPGA;
|
||||
if(module->pf_parse_header == adts_read_header)
|
||||
{
|
||||
uint8_t *extra = track->format->extradata = module->extradata;
|
||||
unsigned int sr_id;
|
||||
for( sr_id = 0; sr_id < 13; sr_id++ )
|
||||
if( mpga_sample_rate_adts[sr_id] == module->sample_rate ) break;
|
||||
extra[0] = (module->version << 3) | ((sr_id & 0xe) >> 1);
|
||||
extra[1] = ((sr_id & 0x1) << 7) | (module->channels << 3);
|
||||
track->format->extradata_size = 2;
|
||||
track->format->codec = VC_CONTAINER_CODEC_MP4A;
|
||||
}
|
||||
track->format->flags |= VC_CONTAINER_ES_FORMAT_FLAG_FRAMED;
|
||||
track->is_enabled = true;
|
||||
track->format->type->audio.channels = module->channels;
|
||||
track->format->type->audio.sample_rate = module->sample_rate;
|
||||
track->format->type->audio.bits_per_sample = 0;
|
||||
track->format->type->audio.block_align = 1;
|
||||
|
||||
module->data_offset = STREAM_POSITION(p_ctx);
|
||||
|
||||
/* Look for VBR headers within the first frame */
|
||||
status = mpga_read_vbr_headers(p_ctx);
|
||||
if (status && status != VC_CONTAINER_ERROR_NOT_FOUND) goto error;
|
||||
|
||||
/* If we couldn't get this information from VBR headers, try to determine
|
||||
file size, bitrate, number of frames and duration */
|
||||
if (!module->data_size)
|
||||
module->data_size = MAX(p_ctx->priv->io->size - module->data_offset, INT64_C(0));
|
||||
|
||||
if (!module->bitrate)
|
||||
{
|
||||
if (STREAM_SEEKABLE(p_ctx))
|
||||
{
|
||||
/* Scan past a few hundred frames (audio will often have
|
||||
silence in the beginning so we need to see more than
|
||||
just a few frames) and estimate bitrate */
|
||||
for (i = 0; i < 256; ++i)
|
||||
if (mpga_reader_read(p_ctx, NULL, VC_CONTAINER_READ_FLAG_SKIP)) break;
|
||||
/* Seek back to start of data */
|
||||
SEEK(p_ctx, module->data_offset);
|
||||
module->frame_index = 0;
|
||||
module->frame_offset = INT64_C(0);
|
||||
module->frame_time_pos = mpga_calculate_frame_time(p_ctx);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Bitrate will be correct for CBR only */
|
||||
module->bitrate = module->frame_bitrate;
|
||||
}
|
||||
}
|
||||
|
||||
track->format->bitrate = module->bitrate;
|
||||
|
||||
if (!module->num_frames)
|
||||
{
|
||||
module->num_frames = (module->data_size * module->sample_rate * 8LL) /
|
||||
(module->bitrate * module->frame_size_samples);
|
||||
}
|
||||
|
||||
if (!p_ctx->duration && module->bitrate)
|
||||
{
|
||||
p_ctx->duration = (INT64_C(8000000) * module->data_size) / module->bitrate;
|
||||
}
|
||||
|
||||
p_ctx->priv->pf_close = mpga_reader_close;
|
||||
p_ctx->priv->pf_read = mpga_reader_read;
|
||||
p_ctx->priv->pf_seek = mpga_reader_seek;
|
||||
|
||||
if(STREAM_SEEKABLE(p_ctx)) p_ctx->capabilities |= VC_CONTAINER_CAPS_CAN_SEEK;
|
||||
|
||||
if(STREAM_STATUS(p_ctx) != VC_CONTAINER_SUCCESS) goto error;
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
|
||||
error:
|
||||
if(status == VC_CONTAINER_SUCCESS || status == VC_CONTAINER_ERROR_EOS)
|
||||
status = VC_CONTAINER_ERROR_FORMAT_INVALID;
|
||||
LOG_DEBUG(p_ctx, "error opening stream (%i)", status);
|
||||
if (p_ctx->tracks_num != 0)
|
||||
vc_container_free_track(p_ctx, p_ctx->tracks[0]);
|
||||
p_ctx->tracks = NULL;
|
||||
p_ctx->tracks_num = 0;
|
||||
if (module) free(module);
|
||||
p_ctx->priv->module = NULL;
|
||||
return status;
|
||||
}
|
||||
|
||||
/********************************************************************************
|
||||
Entrypoint function
|
||||
********************************************************************************/
|
||||
|
||||
#if !defined(ENABLE_CONTAINERS_STANDALONE) && defined(__HIGHC__)
|
||||
# pragma weak reader_open mpga_reader_open
|
||||
#endif
|
431
gfx/include/userland/containers/mpgv/mpgv_packetizer.c
Normal file
431
gfx/include/userland/containers/mpgv/mpgv_packetizer.c
Normal file
@ -0,0 +1,431 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* Implementation of an MPEG1/2 video packetizer.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "containers/packetizers.h"
|
||||
#include "containers/core/packetizers_private.h"
|
||||
#include "containers/core/containers_common.h"
|
||||
#include "containers/core/containers_logging.h"
|
||||
#include "containers/core/containers_time.h"
|
||||
#include "containers/core/containers_utils.h"
|
||||
#include "containers/core/containers_bytestream.h"
|
||||
|
||||
/** Arbitrary number which should be sufficiently high so that no sane frame will
|
||||
* be bigger than that. */
|
||||
#define MAX_FRAME_SIZE (1920*1088*2)
|
||||
|
||||
static uint8_t mpgv_startcode[3] = {0x0, 0x0, 0x1};
|
||||
|
||||
#define PICTURE_CODING_TYPE_I 0x1
|
||||
#define PICTURE_CODING_TYPE_P 0x2
|
||||
#define PICTURE_CODING_TYPE_B 0x3
|
||||
|
||||
VC_CONTAINER_STATUS_T mpgv_packetizer_open( VC_PACKETIZER_T * );
|
||||
|
||||
/*****************************************************************************/
|
||||
typedef struct VC_PACKETIZER_MODULE_T {
|
||||
enum {
|
||||
STATE_SYNC = 0,
|
||||
STATE_SYNC_NEXT,
|
||||
STATE_FRAME_DONE,
|
||||
STATE_UNIT_HEADER,
|
||||
STATE_UNIT_SEQUENCE,
|
||||
STATE_UNIT_GROUP,
|
||||
STATE_UNIT_PICTURE,
|
||||
STATE_UNIT_SLICE,
|
||||
STATE_UNIT_OTHER,
|
||||
STATE_DATA,
|
||||
} state;
|
||||
|
||||
size_t frame_size;
|
||||
size_t unit_offset;
|
||||
|
||||
unsigned int seen_sequence_header;
|
||||
unsigned int seen_picture_header;
|
||||
unsigned int seen_slice;
|
||||
unsigned int lost_sync;
|
||||
|
||||
unsigned int picture_type;
|
||||
unsigned int picture_temporal_ref;
|
||||
int64_t pts;
|
||||
int64_t dts;
|
||||
|
||||
uint32_t bytes_read;
|
||||
|
||||
unsigned int width, height;
|
||||
unsigned int frame_rate_num, frame_rate_den;
|
||||
unsigned int aspect_ratio_num, aspect_ratio_den;
|
||||
bool low_delay;
|
||||
|
||||
} VC_PACKETIZER_MODULE_T;
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T mpgv_packetizer_close( VC_PACKETIZER_T *p_ctx )
|
||||
{
|
||||
free(p_ctx->priv->module);
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T mpgv_packetizer_reset( VC_PACKETIZER_T *p_ctx )
|
||||
{
|
||||
VC_PACKETIZER_MODULE_T *module = p_ctx->priv->module;
|
||||
module->lost_sync = 0;
|
||||
module->state = STATE_SYNC;
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T mpgv_read_sequence_header(VC_CONTAINER_BYTESTREAM_T *stream,
|
||||
size_t offset, unsigned int *width, unsigned int *height,
|
||||
unsigned int *frame_rate_num, unsigned int *frame_rate_den,
|
||||
unsigned int *aspect_ratio_num, unsigned int *aspect_ratio_den)
|
||||
{
|
||||
static const int frame_rate[16][2] =
|
||||
{ {0, 0}, {24000, 1001}, {24, 1}, {25, 1}, {30000, 1001}, {30, 1}, {50, 1},
|
||||
{60000, 1001}, {60, 1},
|
||||
/* Unofficial values */
|
||||
{15, 1001}, /* From Xing */
|
||||
{5, 1001}, {10, 1001}, {12, 1001}, {15, 1001} /* From libmpeg3 */ };
|
||||
static const int aspect_ratio[16][2] =
|
||||
{ {0, 0}, {1, 1}, {4, 3}, {16, 9}, {221, 100} };
|
||||
|
||||
VC_CONTAINER_STATUS_T status;
|
||||
unsigned int w, h, fr, ar;
|
||||
int64_t ar_num, ar_den, div;
|
||||
uint8_t header[8];
|
||||
|
||||
status = bytestream_peek_at( stream, offset, header, sizeof(header));
|
||||
if(status != VC_CONTAINER_SUCCESS)
|
||||
return status;
|
||||
|
||||
w = (header[4] << 4) | (header[5] >> 4);
|
||||
h = ((header[5]&0x0f) << 8) | header[6];
|
||||
ar = header[7] >> 4;
|
||||
fr = header[7]&0x0f;
|
||||
if (!w || !h || !ar || !fr)
|
||||
return VC_CONTAINER_ERROR_CORRUPTED;
|
||||
|
||||
*width = w;
|
||||
*height = h;
|
||||
*frame_rate_num = frame_rate[fr][0];
|
||||
*frame_rate_den = frame_rate[fr][1];
|
||||
ar_num = (int64_t)aspect_ratio[ar][0] * h;
|
||||
ar_den = (int64_t)aspect_ratio[ar][1] * w;
|
||||
div = vc_container_maths_gcd(ar_num, ar_den);
|
||||
if (div)
|
||||
{
|
||||
ar_num /= div;
|
||||
ar_den /= div;
|
||||
}
|
||||
*aspect_ratio_num = ar_num;
|
||||
*aspect_ratio_den = ar_den;
|
||||
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T mpgv_read_picture_header(VC_CONTAINER_BYTESTREAM_T *stream,
|
||||
size_t offset, unsigned int *type, unsigned int *temporal_ref)
|
||||
{
|
||||
VC_CONTAINER_STATUS_T status;
|
||||
uint8_t h[2];
|
||||
|
||||
status = bytestream_peek_at(stream, offset + sizeof(mpgv_startcode) + 1, h, sizeof(h));
|
||||
if(status != VC_CONTAINER_SUCCESS)
|
||||
return status;
|
||||
|
||||
*temporal_ref = (h[0] << 2) | (h[1] >> 6);
|
||||
*type = (h[1] >> 3) & 0x7;
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T mpgv_update_format( VC_PACKETIZER_T *p_ctx )
|
||||
{
|
||||
VC_PACKETIZER_MODULE_T *module = p_ctx->priv->module;
|
||||
|
||||
LOG_DEBUG(0, "mpgv format: width %i, height %i, rate %i/%i, ar %i/%i",
|
||||
module->width, module->height, module->frame_rate_num, module->frame_rate_den,
|
||||
module->aspect_ratio_num, module->aspect_ratio_den);
|
||||
|
||||
p_ctx->out->type->video.width = p_ctx->out->type->video.visible_width = module->width;
|
||||
p_ctx->out->type->video.height = p_ctx->out->type->video.visible_height = module->height;
|
||||
p_ctx->out->type->video.par_num = module->aspect_ratio_num;
|
||||
p_ctx->out->type->video.par_den = module->aspect_ratio_den;
|
||||
p_ctx->out->type->video.frame_rate_num = module->frame_rate_num;
|
||||
p_ctx->out->type->video.frame_rate_den = module->frame_rate_den;
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T mpgv_packetizer_packetize( VC_PACKETIZER_T *p_ctx,
|
||||
VC_CONTAINER_PACKET_T *out, VC_PACKETIZER_FLAGS_T flags)
|
||||
{
|
||||
VC_PACKETIZER_MODULE_T *module = p_ctx->priv->module;
|
||||
VC_CONTAINER_BYTESTREAM_T *stream = &p_ctx->priv->stream;
|
||||
VC_CONTAINER_TIME_T *time = &p_ctx->priv->time;
|
||||
VC_CONTAINER_STATUS_T status;
|
||||
uint8_t header[4];
|
||||
size_t offset;
|
||||
|
||||
while(1) switch (module->state)
|
||||
{
|
||||
case STATE_SYNC:
|
||||
offset = 0;
|
||||
status = bytestream_find_startcode( stream, &offset,
|
||||
mpgv_startcode, sizeof(mpgv_startcode) );
|
||||
|
||||
if(offset && !module->lost_sync)
|
||||
LOG_DEBUG(0, "lost sync");
|
||||
|
||||
bytestream_skip(stream, offset);
|
||||
module->lost_sync += offset;
|
||||
|
||||
if(status != VC_CONTAINER_SUCCESS)
|
||||
return VC_CONTAINER_ERROR_INCOMPLETE_DATA; /* We need more data */
|
||||
|
||||
if(module->lost_sync)
|
||||
LOG_DEBUG(0, "recovered sync after %i bytes", module->lost_sync);
|
||||
module->lost_sync = 0;
|
||||
module->state = STATE_UNIT_HEADER;
|
||||
module->frame_size = 0;
|
||||
module->unit_offset = 0;
|
||||
/* fall through to the next state */
|
||||
|
||||
case STATE_UNIT_HEADER:
|
||||
status = bytestream_peek_at( stream, module->unit_offset, header, sizeof(header));
|
||||
if(status != VC_CONTAINER_SUCCESS)
|
||||
{
|
||||
if (!(flags & VC_PACKETIZER_FLAG_FLUSH) ||
|
||||
!module->seen_picture_header || !module->seen_slice)
|
||||
return VC_CONTAINER_ERROR_INCOMPLETE_DATA;
|
||||
module->state = STATE_FRAME_DONE;
|
||||
break;
|
||||
}
|
||||
|
||||
#if defined(ENABLE_CONTAINERS_LOG_FORMAT_VERBOSE)
|
||||
LOG_DEBUG(0, "found unit (%x)", header[3]);
|
||||
#endif
|
||||
|
||||
/* Detect start of new frame */
|
||||
if(module->seen_picture_header && module->seen_slice &&
|
||||
(header[3] == 0x00 /* A picture header */ ||
|
||||
(header[3] > 0xAF && header[3] != 0xB7) /* Not a slice or sequence end */))
|
||||
{
|
||||
module->state = STATE_FRAME_DONE;
|
||||
break;
|
||||
}
|
||||
|
||||
module->frame_size += sizeof(mpgv_startcode);
|
||||
module->state = STATE_SYNC_NEXT;
|
||||
/* fall through to the next state */
|
||||
|
||||
case STATE_SYNC_NEXT:
|
||||
status = bytestream_find_startcode( stream, &module->frame_size,
|
||||
mpgv_startcode, sizeof(mpgv_startcode) );
|
||||
|
||||
/* Sanity check the size of frames. This makes sure we don't endlessly accumulate data
|
||||
* to make up a new frame. */
|
||||
if(module->frame_size > p_ctx->max_frame_size)
|
||||
{
|
||||
LOG_ERROR(0, "frame too big (%i/%i), dropping", module->frame_size, p_ctx->max_frame_size);
|
||||
bytestream_skip(stream, module->frame_size);
|
||||
module->state = STATE_SYNC;
|
||||
break;
|
||||
}
|
||||
if(status != VC_CONTAINER_SUCCESS)
|
||||
{
|
||||
if (!(flags & VC_PACKETIZER_FLAG_FLUSH) ||
|
||||
!module->seen_picture_header || !module->seen_slice)
|
||||
return VC_CONTAINER_ERROR_INCOMPLETE_DATA;
|
||||
module->state = STATE_FRAME_DONE;
|
||||
break;
|
||||
}
|
||||
|
||||
bytestream_peek_at( stream, module->unit_offset, header, sizeof(header));
|
||||
|
||||
/* Drop everything until we've seen a sequence header */
|
||||
if(header[3] != 0xB3 && !module->seen_sequence_header)
|
||||
{
|
||||
LOG_DEBUG(0, "waiting for sequence header, dropping %i bytes", module->frame_size);
|
||||
module->state = STATE_UNIT_HEADER;
|
||||
bytestream_skip(stream, module->frame_size);
|
||||
module->unit_offset = module->frame_size = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if(header[3] == 0x00)
|
||||
module->state = STATE_UNIT_PICTURE;
|
||||
else if(header[3] >= 0x01 && header[3] <= 0xAF)
|
||||
module->state = STATE_UNIT_SLICE;
|
||||
else if(header[3] == 0xB3)
|
||||
module->state = STATE_UNIT_SEQUENCE;
|
||||
else if(header[3] == 0xB8)
|
||||
module->state = STATE_UNIT_GROUP;
|
||||
else
|
||||
module->state = STATE_UNIT_OTHER;
|
||||
break;
|
||||
|
||||
case STATE_UNIT_SEQUENCE:
|
||||
status = mpgv_read_sequence_header(stream, module->unit_offset, &module->width, &module->height,
|
||||
&module->frame_rate_num, &module->frame_rate_den, &module->aspect_ratio_num, &module->aspect_ratio_den);
|
||||
if(status != VC_CONTAINER_SUCCESS && !module->seen_sequence_header)
|
||||
{
|
||||
/* We need a sequence header so drop everything until we see one */
|
||||
LOG_DEBUG(0, "invalid first sequence header, dropping %i bytes", module->frame_size);
|
||||
bytestream_skip(stream, module->frame_size);
|
||||
module->state = STATE_SYNC;
|
||||
break;
|
||||
}
|
||||
mpgv_update_format(p_ctx);
|
||||
module->seen_sequence_header = true;
|
||||
vc_container_time_set_samplerate(time, module->frame_rate_num, module->frame_rate_den);
|
||||
module->state = STATE_UNIT_HEADER;
|
||||
module->unit_offset = module->frame_size;
|
||||
break;
|
||||
|
||||
case STATE_UNIT_PICTURE:
|
||||
status = mpgv_read_picture_header(stream, module->unit_offset, &module->picture_type, &module->picture_temporal_ref);
|
||||
if(status != VC_CONTAINER_SUCCESS)
|
||||
return VC_CONTAINER_ERROR_INCOMPLETE_DATA;
|
||||
module->seen_picture_header = true;
|
||||
module->state = STATE_UNIT_HEADER;
|
||||
module->unit_offset = module->frame_size;
|
||||
break;
|
||||
|
||||
case STATE_UNIT_SLICE:
|
||||
module->seen_slice = true;
|
||||
module->state = STATE_UNIT_HEADER;
|
||||
module->unit_offset = module->frame_size;
|
||||
break;
|
||||
|
||||
case STATE_UNIT_GROUP:
|
||||
case STATE_UNIT_OTHER:
|
||||
module->state = STATE_UNIT_HEADER;
|
||||
module->unit_offset = module->frame_size;
|
||||
break;
|
||||
|
||||
case STATE_FRAME_DONE:
|
||||
bytestream_get_timestamps(stream, &module->pts, &module->dts, false);
|
||||
|
||||
if(module->picture_type == PICTURE_CODING_TYPE_B || module->low_delay)
|
||||
{
|
||||
if(module->pts == VC_CONTAINER_TIME_UNKNOWN)
|
||||
module->pts = module->dts;
|
||||
if(module->dts == VC_CONTAINER_TIME_UNKNOWN)
|
||||
module->dts = module->pts;
|
||||
}
|
||||
vc_container_time_set(time, module->pts);
|
||||
|
||||
module->bytes_read = 0;
|
||||
module->state = STATE_DATA;
|
||||
module->seen_slice = false;
|
||||
module->seen_picture_header = false;
|
||||
|
||||
#if defined(ENABLE_CONTAINERS_LOG_FORMAT_VERBOSE)
|
||||
LOG_DEBUG(0, "new frame, type %x, size %i, temp_ref %i)", module->picture_type,
|
||||
module->frame_size, module->picture_temporal_ref);
|
||||
#endif
|
||||
/* fall through to the next state */
|
||||
|
||||
case STATE_DATA:
|
||||
out->size = module->frame_size - module->bytes_read;
|
||||
out->pts = out->dts = VC_CONTAINER_TIME_UNKNOWN;
|
||||
out->flags = VC_CONTAINER_PACKET_FLAG_FRAME_END;
|
||||
|
||||
if(!module->bytes_read)
|
||||
{
|
||||
out->pts = module->pts;
|
||||
out->dts = module->dts;
|
||||
out->flags |= VC_CONTAINER_PACKET_FLAG_FRAME_START;
|
||||
}
|
||||
|
||||
if(flags & VC_PACKETIZER_FLAG_INFO)
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
|
||||
if(flags & VC_PACKETIZER_FLAG_SKIP)
|
||||
{
|
||||
bytestream_skip( stream, out->size );
|
||||
}
|
||||
else
|
||||
{
|
||||
out->size = MIN(out->size, out->buffer_size);
|
||||
bytestream_get( stream, out->data, out->size );
|
||||
}
|
||||
module->bytes_read += out->size;
|
||||
|
||||
if(module->bytes_read == module->frame_size)
|
||||
{
|
||||
vc_container_time_add(time, 1);
|
||||
module->state = STATE_UNIT_HEADER;
|
||||
module->frame_size = 0;
|
||||
module->unit_offset = 0;
|
||||
}
|
||||
else
|
||||
out->flags &= ~VC_CONTAINER_PACKET_FLAG_FRAME_END;
|
||||
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
|
||||
default:
|
||||
break;
|
||||
};
|
||||
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_CONTAINER_STATUS_T mpgv_packetizer_open( VC_PACKETIZER_T *p_ctx )
|
||||
{
|
||||
VC_PACKETIZER_MODULE_T *module;
|
||||
|
||||
if(p_ctx->in->codec != VC_CONTAINER_CODEC_MP1V &&
|
||||
p_ctx->in->codec != VC_CONTAINER_CODEC_MP2V)
|
||||
return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
|
||||
p_ctx->priv->module = module = malloc(sizeof(*module));
|
||||
if(!module)
|
||||
return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
|
||||
memset(module, 0, sizeof(*module));
|
||||
|
||||
vc_container_format_copy( p_ctx->out, p_ctx->in, 0);
|
||||
p_ctx->max_frame_size = MAX_FRAME_SIZE;
|
||||
p_ctx->priv->pf_close = mpgv_packetizer_close;
|
||||
p_ctx->priv->pf_packetize = mpgv_packetizer_packetize;
|
||||
p_ctx->priv->pf_reset = mpgv_packetizer_reset;
|
||||
LOG_DEBUG(0, "using mpeg video packetizer");
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_PACKETIZER_REGISTER(mpgv_packetizer_open, "mpgv");
|
263
gfx/include/userland/containers/net/net_sockets.h
Normal file
263
gfx/include/userland/containers/net/net_sockets.h
Normal file
@ -0,0 +1,263 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef VC_NET_SOCKETS_H
|
||||
#define VC_NET_SOCKETS_H
|
||||
|
||||
/** \file net_sockets.h
|
||||
* Abstraction layer for socket-style network communication, to enable porting
|
||||
* between platforms.
|
||||
*
|
||||
* Does not support IPv6 multicast.
|
||||
*/
|
||||
|
||||
#include "containers/containers_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Status codes that can occur in a socket instance. */
|
||||
typedef enum {
|
||||
VC_CONTAINER_NET_SUCCESS = 0, /**< No error */
|
||||
VC_CONTAINER_NET_ERROR_GENERAL, /**< An unrecognised error has occurred */
|
||||
VC_CONTAINER_NET_ERROR_INVALID_SOCKET, /**< Invalid socket passed to function */
|
||||
VC_CONTAINER_NET_ERROR_NOT_ALLOWED, /**< The operation requested is not allowed */
|
||||
VC_CONTAINER_NET_ERROR_INVALID_PARAMETER, /**< An invalid parameter was passed in */
|
||||
VC_CONTAINER_NET_ERROR_NO_MEMORY, /**< Failure due to lack of memory */
|
||||
VC_CONTAINER_NET_ERROR_ACCESS_DENIED, /**< Permission denied */
|
||||
VC_CONTAINER_NET_ERROR_TOO_BIG, /**< Too many handles already open */
|
||||
VC_CONTAINER_NET_ERROR_WOULD_BLOCK, /**< Asynchronous operation would block */
|
||||
VC_CONTAINER_NET_ERROR_IN_PROGRESS, /**< An operation is already in progress on this socket */
|
||||
VC_CONTAINER_NET_ERROR_IN_USE, /**< The address/port is already in use */
|
||||
VC_CONTAINER_NET_ERROR_NETWORK, /**< Network is unavailable */
|
||||
VC_CONTAINER_NET_ERROR_CONNECTION_LOST, /**< The connection has been lost, closed by network, etc. */
|
||||
VC_CONTAINER_NET_ERROR_NOT_CONNECTED, /**< The socket is not connected */
|
||||
VC_CONTAINER_NET_ERROR_TIMED_OUT, /**< Operation timed out */
|
||||
VC_CONTAINER_NET_ERROR_CONNECTION_REFUSED, /**< Connection was refused by target */
|
||||
VC_CONTAINER_NET_ERROR_HOST_NOT_FOUND, /**< Target address could not be resolved */
|
||||
VC_CONTAINER_NET_ERROR_TRY_AGAIN, /**< A temporary failure occurred that may clear */
|
||||
} vc_container_net_status_t;
|
||||
|
||||
/** Operations that can be applied to sockets */
|
||||
typedef enum {
|
||||
/** Set the buffer size used on the socket
|
||||
* arg1: uint32_t - New buffer size in bytes */
|
||||
VC_CONTAINER_NET_CONTROL_SET_READ_BUFFER_SIZE = 1,
|
||||
/** Set the timeout to be used on read operations
|
||||
* arg1: uint32_t - New timeout in milliseconds, or INFINITE_TIMEOUT_MS */
|
||||
VC_CONTAINER_NET_CONTROL_SET_READ_TIMEOUT_MS,
|
||||
} vc_container_net_control_t;
|
||||
|
||||
/** Container Input / Output Context.
|
||||
* This is an opaque structure that defines the context for a socket instance.
|
||||
* The details of the structure are contained within the platform implementation. */
|
||||
typedef struct vc_container_net_tag VC_CONTAINER_NET_T;
|
||||
|
||||
/** \name Socket open flags
|
||||
* The following flags can be used when opening a network socket. */
|
||||
/* @{ */
|
||||
typedef uint32_t vc_container_net_open_flags_t;
|
||||
/** Connected stream socket, rather than connectionless datagram socket */
|
||||
#define VC_CONTAINER_NET_OPEN_FLAG_STREAM 1
|
||||
/** Force use of IPv4 addressing */
|
||||
#define VC_CONTAINER_NET_OPEN_FLAG_FORCE_IP4 2
|
||||
/** Force use of IPv6 addressing */
|
||||
#define VC_CONTAINER_NET_OPEN_FLAG_FORCE_IP6 6
|
||||
/** Use IPv4 broadcast address for datagram delivery */
|
||||
#define VC_CONTAINER_NET_OPEN_FLAG_IP4_BROADCAST 8
|
||||
/* @} */
|
||||
|
||||
/** Mask of bits used in forcing address type */
|
||||
#define VC_CONTAINER_NET_OPEN_FLAG_FORCE_MASK 6
|
||||
|
||||
/** Blocks until data is available, or an error occurs.
|
||||
* Used with the VC_CONTAINER_NET_CONTROL_SET_READ_TIMEOUT_MS control operation. */
|
||||
#define INFINITE_TIMEOUT_MS 0xFFFFFFFFUL
|
||||
|
||||
|
||||
/** Opens a network socket instance.
|
||||
* The network address can be a host name, dotted IP4, hex IP6 address or NULL. Passing NULL
|
||||
* signifies the socket is either to be used as a datagram receiver or a stream server,
|
||||
* depending on the flags.
|
||||
* \ref VC_CONTAINER_NET_OPEN_FLAG_STREAM will open the socket for connected streaming. The default
|
||||
* is to use connectionless datagrams.
|
||||
* \ref VC_CONTAINER_NET_OPEN_FLAG_FORCE_IP4 will force the use of IPv4 addressing or fail to open
|
||||
* the socket. The default is to pick the first available.
|
||||
* \ref VC_CONTAINER_NET_OPEN_FLAG_FORCE_IP6 will force the use of IPv6 addressing or fail to open
|
||||
* the socket. The default is to pick the first available.
|
||||
* \ref VC_CONTAINER_NET_OPEN_FLAG_IP4_BROADCAST will use IPv4 broadcast addressing for a datagram
|
||||
* sender. Use with an IPv6 address, stream socket or datagram receiver will raise an error.
|
||||
* If the p_status parameter is not NULL, the status code will be written to it to indicate the
|
||||
* reason for failure, or VC_CONTAINER_NET_SUCCESS on success.
|
||||
* Sockets shall be bound and connected as necessary. Stream server sockets shall further need
|
||||
* to have vc_container_net_listen and vc_container_net_accept called on them before data can be transferred.
|
||||
*
|
||||
* \param address Network address or NULL.
|
||||
* \param port Network port or well-known name. This is the local port for receivers/servers.
|
||||
* \param flags Flags controlling socket type.
|
||||
* \param p_status Optional pointer to variable to receive status of operation.
|
||||
* \return The socket instance or NULL on error. */
|
||||
VC_CONTAINER_NET_T *vc_container_net_open( const char *address, const char *port,
|
||||
vc_container_net_open_flags_t flags, vc_container_net_status_t *p_status );
|
||||
|
||||
/** Closes a network socket instance.
|
||||
* The p_ctx pointer must not be used after it has been closed.
|
||||
*
|
||||
* \param p_ctx The socket instance to close.
|
||||
* \return The status code for closing the socket. */
|
||||
vc_container_net_status_t vc_container_net_close( VC_CONTAINER_NET_T *p_ctx );
|
||||
|
||||
/** Query the latest status of the socket.
|
||||
*
|
||||
* \param p_ctx The socket instance.
|
||||
* \return The status of the socket. */
|
||||
vc_container_net_status_t vc_container_net_status( VC_CONTAINER_NET_T *p_ctx );
|
||||
|
||||
/** Read data from the socket.
|
||||
* The function will read up to the requested number of bytes into the buffer.
|
||||
* If there is no data immediately available to read, the function will block
|
||||
* until data arrives, an error occurs or the timeout is reached (if set).
|
||||
* When the function returns zero, the socket may have been closed, an error
|
||||
* may have occurred, a zero length datagram received, or the timeout reached.
|
||||
* Check vc_container_net_status() to differentiate.
|
||||
* Attempting to read on a datagram sender socket will trigger an error.
|
||||
*
|
||||
* \param p_ctx The socket instance.
|
||||
* \param buffer The buffer into which bytes will be read.
|
||||
* \param size The maximum number of bytes to read.
|
||||
* \return The number of bytes actually read. */
|
||||
size_t vc_container_net_read( VC_CONTAINER_NET_T *p_ctx, void *buffer, size_t size );
|
||||
|
||||
/** Write data to the socket.
|
||||
* If the socket cannot send the requested number of bytes in one go, the function
|
||||
* will return a value smaller than size.
|
||||
* Attempting to write on a datagram receiver socket will trigger an error.
|
||||
*
|
||||
* \param p_ctx The socket instance.
|
||||
* \param buffer The buffer from which bytes will be written.
|
||||
* \param size The maximum number of bytes to write.
|
||||
* \return The number of bytes actually written. */
|
||||
size_t vc_container_net_write( VC_CONTAINER_NET_T *p_ctx, const void *buffer, size_t size );
|
||||
|
||||
/** Start a stream server socket listening for connections from clients.
|
||||
* Attempting to use this on anything other than a stream server socket shall
|
||||
* trigger an error.
|
||||
*
|
||||
* \param p_ctx The socket instance.
|
||||
* \param maximum_connections The maximum number of queued connections to allow.
|
||||
* \return The status of the socket. */
|
||||
vc_container_net_status_t vc_container_net_listen( VC_CONTAINER_NET_T *p_ctx, uint32_t maximum_connections );
|
||||
|
||||
/** Accept a client connection on a listening stream server socket.
|
||||
* Attempting to use this on anything other than a listening stream server socket
|
||||
* shall trigger an error.
|
||||
* When a client connection is made, the new instance representing it is returned
|
||||
* via pp_client_ctx.
|
||||
*
|
||||
* \param p_server ctx The server socket instance.
|
||||
* \param pp_client_ctx The address where the pointer to the new client's socket
|
||||
* instance is written.
|
||||
* \return The status of the socket. */
|
||||
vc_container_net_status_t vc_container_net_accept( VC_CONTAINER_NET_T *p_server_ctx, VC_CONTAINER_NET_T **pp_client_ctx );
|
||||
|
||||
/** Non-blocking check for data being available to read.
|
||||
* If an error occurs, the function will return false and the error can be
|
||||
* obtained using socket_status().
|
||||
*
|
||||
* \param p_ctx The socket instance.
|
||||
* \return True if there is data available to read immediately. */
|
||||
bool vc_container_net_is_data_available( VC_CONTAINER_NET_T *p_ctx );
|
||||
|
||||
/** Returns the maximum size of a datagram in bytes, for sending or receiving.
|
||||
* The limit for reading from or writing to stream sockets will generally be
|
||||
* greater than this value, although the call can also be made on such sockets.
|
||||
*
|
||||
* \param p_ctx The socket instance.
|
||||
* \return The maximum size of a datagram in bytes. */
|
||||
size_t vc_container_net_maximum_datagram_size( VC_CONTAINER_NET_T *p_ctx );
|
||||
|
||||
/** Get the DNS name or IP address of a stream server client, if connected.
|
||||
* The length of the name will be limited by name_len, taking into account a
|
||||
* terminating NUL character.
|
||||
* Calling this function on a non-stream server instance, or one that is not
|
||||
* connected to a client, will result in an error status.
|
||||
*
|
||||
* \param p_ctx The socket instance.
|
||||
* \param name Pointer where the name should be written.
|
||||
* \param name_len Maximum number of characters to write to name.
|
||||
* \return The status of the socket. */
|
||||
vc_container_net_status_t vc_container_net_get_client_name( VC_CONTAINER_NET_T *p_ctx, char *name, size_t name_len );
|
||||
|
||||
/** Get the port of a stream server client, if connected.
|
||||
* The port is written to the address in host order.
|
||||
* Calling this function on a non-stream server instance, or one that is not
|
||||
* connected to a client, will result in an error status.
|
||||
*
|
||||
* \param p_ctx The socket instance.
|
||||
* \param port Pointer where the port should be written.
|
||||
* \return The status of the socket. */
|
||||
vc_container_net_status_t vc_container_net_get_client_port( VC_CONTAINER_NET_T *p_ctx , unsigned short *port );
|
||||
|
||||
/** Perform a control operation on the socket.
|
||||
* See vc_container_net_control_t for more details.
|
||||
*
|
||||
* \param p_ctx The socket instance.
|
||||
* \param operation The control operation to perform.
|
||||
* \param args Variable list of additional arguments to the operation.
|
||||
* \return The status of the socket. */
|
||||
vc_container_net_status_t vc_container_net_control( VC_CONTAINER_NET_T *p_ctx, vc_container_net_control_t operation, va_list args);
|
||||
|
||||
/** Convert a 32-bit unsigned value from network order (big endian) to host order.
|
||||
*
|
||||
* \param value The value to be converted.
|
||||
* \return The converted value. */
|
||||
uint32_t vc_container_net_to_host( uint32_t value );
|
||||
|
||||
/** Convert a 32-bit unsigned value from host order to network order (big endian).
|
||||
*
|
||||
* \param value The value to be converted.
|
||||
* \return The converted value. */
|
||||
uint32_t vc_container_net_from_host( uint32_t value );
|
||||
|
||||
/** Convert a 16-bit unsigned value from network order (big endian) to host order.
|
||||
*
|
||||
* \param value The value to be converted.
|
||||
* \return The converted value. */
|
||||
uint16_t vc_container_net_to_host_16( uint16_t value );
|
||||
|
||||
/** Convert a 16-bit unsigned value from host order to network order (big endian).
|
||||
*
|
||||
* \param value The value to be converted.
|
||||
* \return The converted value. */
|
||||
uint16_t vc_container_net_from_host_16( uint16_t value );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* VC_NET_SOCKETS_H */
|
117
gfx/include/userland/containers/net/net_sockets_bsd.c
Normal file
117
gfx/include/userland/containers/net/net_sockets_bsd.c
Normal file
@ -0,0 +1,117 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "net_sockets.h"
|
||||
#include "net_sockets_priv.h"
|
||||
#include "containers/core/containers_common.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Default maximum datagram size.
|
||||
* This is based on the default Ethernet MTU size, less the IP and UDP headers.
|
||||
*/
|
||||
#define DEFAULT_MAXIMUM_DATAGRAM_SIZE (1500 - 20 - 8)
|
||||
|
||||
/** Maximum socket buffer size to use. */
|
||||
#define MAXIMUM_BUFFER_SIZE 65536
|
||||
|
||||
/*****************************************************************************/
|
||||
vc_container_net_status_t vc_container_net_private_last_error()
|
||||
{
|
||||
switch (errno)
|
||||
{
|
||||
case EACCES: return VC_CONTAINER_NET_ERROR_ACCESS_DENIED;
|
||||
case EFAULT: return VC_CONTAINER_NET_ERROR_INVALID_PARAMETER;
|
||||
case EINVAL: return VC_CONTAINER_NET_ERROR_INVALID_PARAMETER;
|
||||
case EMFILE: return VC_CONTAINER_NET_ERROR_TOO_BIG;
|
||||
case EWOULDBLOCK: return VC_CONTAINER_NET_ERROR_WOULD_BLOCK;
|
||||
case EINPROGRESS: return VC_CONTAINER_NET_ERROR_IN_PROGRESS;
|
||||
case EALREADY: return VC_CONTAINER_NET_ERROR_IN_PROGRESS;
|
||||
case EADDRINUSE: return VC_CONTAINER_NET_ERROR_IN_USE;
|
||||
case EADDRNOTAVAIL: return VC_CONTAINER_NET_ERROR_INVALID_PARAMETER;
|
||||
case ENETDOWN: return VC_CONTAINER_NET_ERROR_NETWORK;
|
||||
case ENETUNREACH: return VC_CONTAINER_NET_ERROR_NETWORK;
|
||||
case ENETRESET: return VC_CONTAINER_NET_ERROR_CONNECTION_LOST;
|
||||
case ECONNABORTED: return VC_CONTAINER_NET_ERROR_CONNECTION_LOST;
|
||||
case ECONNRESET: return VC_CONTAINER_NET_ERROR_CONNECTION_LOST;
|
||||
case ENOBUFS: return VC_CONTAINER_NET_ERROR_NO_MEMORY;
|
||||
case ENOTCONN: return VC_CONTAINER_NET_ERROR_NOT_CONNECTED;
|
||||
case ESHUTDOWN: return VC_CONTAINER_NET_ERROR_CONNECTION_LOST;
|
||||
case ETIMEDOUT: return VC_CONTAINER_NET_ERROR_TIMED_OUT;
|
||||
case ECONNREFUSED: return VC_CONTAINER_NET_ERROR_CONNECTION_REFUSED;
|
||||
case ELOOP: return VC_CONTAINER_NET_ERROR_INVALID_PARAMETER;
|
||||
case ENAMETOOLONG: return VC_CONTAINER_NET_ERROR_INVALID_PARAMETER;
|
||||
case EHOSTDOWN: return VC_CONTAINER_NET_ERROR_NETWORK;
|
||||
case EHOSTUNREACH: return VC_CONTAINER_NET_ERROR_NETWORK;
|
||||
case EUSERS: return VC_CONTAINER_NET_ERROR_NO_MEMORY;
|
||||
case EDQUOT: return VC_CONTAINER_NET_ERROR_NO_MEMORY;
|
||||
case ESTALE: return VC_CONTAINER_NET_ERROR_INVALID_SOCKET;
|
||||
|
||||
/* All other errors are unexpected, so just map to a general purpose error code. */
|
||||
default:
|
||||
return VC_CONTAINER_NET_ERROR_GENERAL;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
vc_container_net_status_t vc_container_net_private_init()
|
||||
{
|
||||
/* No additional initialization required */
|
||||
return VC_CONTAINER_NET_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
void vc_container_net_private_deinit()
|
||||
{
|
||||
/* No additional deinitialization required */
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
void vc_container_net_private_close( SOCKET_T sock )
|
||||
{
|
||||
close(sock);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
void vc_container_net_private_set_reusable( SOCKET_T sock, bool enable )
|
||||
{
|
||||
int opt = enable ? 1 : 0;
|
||||
|
||||
(void)setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof(opt));
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
size_t vc_container_net_private_maximum_datagram_size( SOCKET_T sock )
|
||||
{
|
||||
(void)sock;
|
||||
|
||||
/* No easy way to determine this, just use the default. */
|
||||
return DEFAULT_MAXIMUM_DATAGRAM_SIZE;
|
||||
}
|
43
gfx/include/userland/containers/net/net_sockets_bsd.h
Normal file
43
gfx/include/userland/containers/net/net_sockets_bsd.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _NET_SOCKETS_BSD_H_
|
||||
#define _NET_SOCKETS_BSD_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/select.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
|
||||
typedef int SOCKET_T;
|
||||
typedef socklen_t SOCKADDR_LEN_T;
|
||||
typedef void *SOCKOPT_CAST_T;
|
||||
#define INVALID_SOCKET -1
|
||||
#define SOCKET_ERROR -1
|
||||
|
||||
#endif /* _NET_SOCKETS_BSD_H_ */
|
619
gfx/include/userland/containers/net/net_sockets_common.c
Normal file
619
gfx/include/userland/containers/net/net_sockets_common.c
Normal file
@ -0,0 +1,619 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "containers/containers.h"
|
||||
#include "containers/core/containers_common.h"
|
||||
#include "containers/core/containers_logging.h"
|
||||
#include "net_sockets.h"
|
||||
#include "net_sockets_priv.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
struct vc_container_net_tag
|
||||
{
|
||||
/** The underlying socket */
|
||||
SOCKET_T socket;
|
||||
/** Last error raised on the socket instance. */
|
||||
vc_container_net_status_t status;
|
||||
/** Simple socket type */
|
||||
vc_container_net_type_t type;
|
||||
/** Socket address, used for sending datagrams. */
|
||||
union {
|
||||
struct sockaddr_storage storage;
|
||||
struct sockaddr sa;
|
||||
struct sockaddr_in in;
|
||||
struct sockaddr_in6 in6;
|
||||
} to_addr;
|
||||
/** Number of bytes in to_addr that have been filled. */
|
||||
SOCKADDR_LEN_T to_addr_len;
|
||||
/** Maximum size of datagrams. */
|
||||
size_t max_datagram_size;
|
||||
/** Timeout to use when reading from a socket. INFINITE_TIMEOUT_MS waits forever. */
|
||||
uint32_t read_timeout_ms;
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
static void socket_clear_address(struct sockaddr *p_addr)
|
||||
{
|
||||
switch (p_addr->sa_family)
|
||||
{
|
||||
case AF_INET:
|
||||
{
|
||||
struct sockaddr_in *p_addr_v4 = (struct sockaddr_in *)p_addr;
|
||||
|
||||
memset(&p_addr_v4->sin_addr, 0, sizeof(p_addr_v4->sin_addr));
|
||||
}
|
||||
break;
|
||||
case AF_INET6:
|
||||
{
|
||||
struct sockaddr_in6 *p_addr_v6 = (struct sockaddr_in6 *)p_addr;
|
||||
|
||||
memset(&p_addr_v6->sin6_addr, 0, sizeof(p_addr_v6->sin6_addr));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* Invalid or unsupported address family */
|
||||
vc_container_assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static vc_container_net_status_t socket_set_read_buffer_size(VC_CONTAINER_NET_T *p_ctx,
|
||||
uint32_t buffer_size)
|
||||
{
|
||||
int result;
|
||||
const SOCKOPT_CAST_T optptr = (const SOCKOPT_CAST_T)&buffer_size;
|
||||
|
||||
result = setsockopt(p_ctx->socket, SOL_SOCKET, SO_RCVBUF, optptr, sizeof(buffer_size));
|
||||
|
||||
if (result == SOCKET_ERROR)
|
||||
return vc_container_net_private_last_error();
|
||||
|
||||
return VC_CONTAINER_NET_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static vc_container_net_status_t socket_set_read_timeout_ms(VC_CONTAINER_NET_T *p_ctx,
|
||||
uint32_t timeout_ms)
|
||||
{
|
||||
p_ctx->read_timeout_ms = timeout_ms;
|
||||
return VC_CONTAINER_NET_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static bool socket_wait_for_data( VC_CONTAINER_NET_T *p_ctx, uint32_t timeout_ms )
|
||||
{
|
||||
int result;
|
||||
fd_set set;
|
||||
struct timeval tv;
|
||||
|
||||
if (timeout_ms == INFINITE_TIMEOUT_MS)
|
||||
return true;
|
||||
|
||||
FD_ZERO(&set);
|
||||
FD_SET(p_ctx->socket, &set);
|
||||
tv.tv_sec = timeout_ms / 1000;
|
||||
tv.tv_usec = (timeout_ms - tv.tv_sec * 1000) * 1000;
|
||||
result = select(p_ctx->socket + 1, &set, NULL, NULL, &tv);
|
||||
|
||||
if (result == SOCKET_ERROR)
|
||||
p_ctx->status = vc_container_net_private_last_error();
|
||||
else
|
||||
p_ctx->status = VC_CONTAINER_NET_SUCCESS;
|
||||
|
||||
return (result == 1);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_CONTAINER_NET_T *vc_container_net_open( const char *address, const char *port,
|
||||
vc_container_net_open_flags_t flags, vc_container_net_status_t *p_status )
|
||||
{
|
||||
VC_CONTAINER_NET_T *p_ctx;
|
||||
struct addrinfo hints, *info, *p;
|
||||
int result;
|
||||
vc_container_net_status_t status;
|
||||
SOCKET_T sock = INVALID_SOCKET;
|
||||
|
||||
status = vc_container_net_private_init();
|
||||
if (status != VC_CONTAINER_NET_SUCCESS)
|
||||
{
|
||||
LOG_ERROR(NULL, "vc_container_net_open: platform initialization failure: %d", status);
|
||||
if (p_status)
|
||||
*p_status = status;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p_ctx = (VC_CONTAINER_NET_T *)malloc(sizeof(VC_CONTAINER_NET_T));
|
||||
if (!p_ctx)
|
||||
{
|
||||
if (p_status)
|
||||
*p_status = VC_CONTAINER_NET_ERROR_NO_MEMORY;
|
||||
|
||||
LOG_ERROR(NULL, "vc_container_net_open: malloc fail for VC_CONTAINER_NET_T");
|
||||
vc_container_net_private_deinit();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Initialize the net socket instance structure */
|
||||
memset(p_ctx, 0, sizeof(*p_ctx));
|
||||
p_ctx->socket = INVALID_SOCKET;
|
||||
if (flags & VC_CONTAINER_NET_OPEN_FLAG_STREAM)
|
||||
p_ctx->type = address ? STREAM_CLIENT : STREAM_SERVER;
|
||||
else
|
||||
p_ctx->type = address ? DATAGRAM_SENDER : DATAGRAM_RECEIVER;
|
||||
|
||||
/* Create the address info linked list from the data provided */
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
switch (flags & VC_CONTAINER_NET_OPEN_FLAG_FORCE_MASK)
|
||||
{
|
||||
case 0:
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
break;
|
||||
case VC_CONTAINER_NET_OPEN_FLAG_FORCE_IP4:
|
||||
hints.ai_family = AF_INET;
|
||||
break;
|
||||
case VC_CONTAINER_NET_OPEN_FLAG_FORCE_IP6:
|
||||
hints.ai_family = AF_INET6;
|
||||
break;
|
||||
default:
|
||||
status = VC_CONTAINER_NET_ERROR_INVALID_PARAMETER;
|
||||
LOG_ERROR(NULL, "vc_container_net_open: invalid address forcing flag");
|
||||
goto error;
|
||||
}
|
||||
hints.ai_socktype = (flags & VC_CONTAINER_NET_OPEN_FLAG_STREAM) ? SOCK_STREAM : SOCK_DGRAM;
|
||||
|
||||
result = getaddrinfo(address, port, &hints, &info);
|
||||
if (result)
|
||||
{
|
||||
status = vc_container_net_private_last_error();
|
||||
LOG_ERROR(NULL, "vc_container_net_open: unable to get address info: %d", status);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Not all address infos may be useable. Search for one that is by skipping any
|
||||
* that provoke errors. */
|
||||
for(p = info; (p != NULL) && (sock == INVALID_SOCKET) ; p = p->ai_next)
|
||||
{
|
||||
sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
|
||||
if (sock == INVALID_SOCKET)
|
||||
{
|
||||
status = vc_container_net_private_last_error();
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (p_ctx->type)
|
||||
{
|
||||
case STREAM_CLIENT:
|
||||
/* Simply connect to the given address/port */
|
||||
if (connect(sock, p->ai_addr, p->ai_addrlen) == SOCKET_ERROR)
|
||||
status = vc_container_net_private_last_error();
|
||||
break;
|
||||
|
||||
case DATAGRAM_SENDER:
|
||||
/* Nothing further to do */
|
||||
break;
|
||||
|
||||
case STREAM_SERVER:
|
||||
/* Try to avoid socket reuse timing issues on TCP server sockets */
|
||||
vc_container_net_private_set_reusable(sock, true);
|
||||
|
||||
/* Allow any source address */
|
||||
socket_clear_address(p->ai_addr);
|
||||
|
||||
if (bind(sock, p->ai_addr, p->ai_addrlen) == SOCKET_ERROR)
|
||||
status = vc_container_net_private_last_error();
|
||||
break;
|
||||
|
||||
case DATAGRAM_RECEIVER:
|
||||
/* Allow any source address */
|
||||
socket_clear_address(p->ai_addr);
|
||||
|
||||
if (bind(sock, p->ai_addr, p->ai_addrlen) == SOCKET_ERROR)
|
||||
status = vc_container_net_private_last_error();
|
||||
break;
|
||||
}
|
||||
|
||||
if (status == VC_CONTAINER_NET_SUCCESS)
|
||||
{
|
||||
/* Save addressing information for later use */
|
||||
p_ctx->to_addr_len = p->ai_addrlen;
|
||||
memcpy(&p_ctx->to_addr, p->ai_addr, p->ai_addrlen);
|
||||
} else {
|
||||
vc_container_net_private_close(sock); /* Try next entry in list */
|
||||
sock = INVALID_SOCKET;
|
||||
}
|
||||
}
|
||||
|
||||
freeaddrinfo(info);
|
||||
|
||||
if (sock == INVALID_SOCKET)
|
||||
{
|
||||
LOG_ERROR(NULL, "vc_container_net_open: failed to open socket: %d", status);
|
||||
goto error;
|
||||
}
|
||||
|
||||
p_ctx->socket = sock;
|
||||
p_ctx->max_datagram_size = vc_container_net_private_maximum_datagram_size(sock);
|
||||
p_ctx->read_timeout_ms = INFINITE_TIMEOUT_MS;
|
||||
|
||||
if (p_status)
|
||||
*p_status = VC_CONTAINER_NET_SUCCESS;
|
||||
|
||||
return p_ctx;
|
||||
|
||||
error:
|
||||
if (p_status)
|
||||
*p_status = status;
|
||||
(void)vc_container_net_close(p_ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
vc_container_net_status_t vc_container_net_close( VC_CONTAINER_NET_T *p_ctx )
|
||||
{
|
||||
if (!p_ctx)
|
||||
return VC_CONTAINER_NET_ERROR_INVALID_SOCKET;
|
||||
|
||||
if (p_ctx->socket != INVALID_SOCKET)
|
||||
{
|
||||
vc_container_net_private_close(p_ctx->socket);
|
||||
p_ctx->socket = INVALID_SOCKET;
|
||||
}
|
||||
free(p_ctx);
|
||||
|
||||
vc_container_net_private_deinit();
|
||||
|
||||
return VC_CONTAINER_NET_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
vc_container_net_status_t vc_container_net_status( VC_CONTAINER_NET_T *p_ctx )
|
||||
{
|
||||
if (!p_ctx)
|
||||
return VC_CONTAINER_NET_ERROR_INVALID_SOCKET;
|
||||
return p_ctx->status;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
size_t vc_container_net_read( VC_CONTAINER_NET_T *p_ctx, void *buffer, size_t size )
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
if (!p_ctx)
|
||||
return 0;
|
||||
|
||||
if (!buffer)
|
||||
{
|
||||
p_ctx->status = VC_CONTAINER_NET_ERROR_INVALID_PARAMETER;
|
||||
return 0;
|
||||
}
|
||||
|
||||
p_ctx->status = VC_CONTAINER_NET_SUCCESS;
|
||||
|
||||
switch (p_ctx->type)
|
||||
{
|
||||
case STREAM_CLIENT:
|
||||
case STREAM_SERVER:
|
||||
/* Receive data from the stream */
|
||||
if (socket_wait_for_data(p_ctx, p_ctx->read_timeout_ms))
|
||||
{
|
||||
result = recv(p_ctx->socket, buffer, (int)size, 0);
|
||||
if (!result)
|
||||
p_ctx->status = VC_CONTAINER_NET_ERROR_CONNECTION_LOST;
|
||||
} else
|
||||
p_ctx->status = VC_CONTAINER_NET_ERROR_TIMED_OUT;
|
||||
break;
|
||||
|
||||
case DATAGRAM_RECEIVER:
|
||||
{
|
||||
/* Receive the packet */
|
||||
/* FIXME Potential for data loss, as rest of packet will be lost if buffer was not large enough */
|
||||
if (socket_wait_for_data(p_ctx, p_ctx->read_timeout_ms))
|
||||
{
|
||||
result = recvfrom(p_ctx->socket, buffer, size, 0, &p_ctx->to_addr.sa, &p_ctx->to_addr_len);
|
||||
if (!result)
|
||||
p_ctx->status = VC_CONTAINER_NET_ERROR_CONNECTION_LOST;
|
||||
} else
|
||||
p_ctx->status = VC_CONTAINER_NET_ERROR_TIMED_OUT;
|
||||
}
|
||||
break;
|
||||
|
||||
default: /* DATAGRAM_SENDER */
|
||||
p_ctx->status = VC_CONTAINER_NET_ERROR_NOT_ALLOWED;
|
||||
result = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (result == SOCKET_ERROR)
|
||||
{
|
||||
p_ctx->status = vc_container_net_private_last_error();
|
||||
result = 0;
|
||||
}
|
||||
|
||||
return (size_t)result;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
size_t vc_container_net_write( VC_CONTAINER_NET_T *p_ctx, const void *buffer, size_t size )
|
||||
{
|
||||
int result;
|
||||
|
||||
if (!p_ctx)
|
||||
return 0;
|
||||
|
||||
if (!buffer)
|
||||
{
|
||||
p_ctx->status = VC_CONTAINER_NET_ERROR_INVALID_PARAMETER;
|
||||
return 0;
|
||||
}
|
||||
|
||||
p_ctx->status = VC_CONTAINER_NET_SUCCESS;
|
||||
|
||||
switch (p_ctx->type)
|
||||
{
|
||||
case STREAM_CLIENT:
|
||||
case STREAM_SERVER:
|
||||
/* Send data to the stream */
|
||||
result = send(p_ctx->socket, buffer, (int)size, 0);
|
||||
break;
|
||||
|
||||
case DATAGRAM_SENDER:
|
||||
/* Send the datagram */
|
||||
|
||||
if (size > p_ctx->max_datagram_size)
|
||||
size = p_ctx->max_datagram_size;
|
||||
|
||||
result = sendto(p_ctx->socket, buffer, size, 0, &p_ctx->to_addr.sa, p_ctx->to_addr_len);
|
||||
break;
|
||||
|
||||
default: /* DATAGRAM_RECEIVER */
|
||||
p_ctx->status = VC_CONTAINER_NET_ERROR_NOT_ALLOWED;
|
||||
result = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (result == SOCKET_ERROR)
|
||||
{
|
||||
p_ctx->status = vc_container_net_private_last_error();
|
||||
result = 0;
|
||||
}
|
||||
|
||||
return (size_t)result;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
vc_container_net_status_t vc_container_net_listen( VC_CONTAINER_NET_T *p_ctx, uint32_t maximum_connections )
|
||||
{
|
||||
if (!p_ctx)
|
||||
return VC_CONTAINER_NET_ERROR_INVALID_SOCKET;
|
||||
|
||||
p_ctx->status = VC_CONTAINER_NET_SUCCESS;
|
||||
|
||||
if (p_ctx->type == STREAM_SERVER)
|
||||
{
|
||||
if (listen(p_ctx->socket, maximum_connections) == SOCKET_ERROR)
|
||||
p_ctx->status = vc_container_net_private_last_error();
|
||||
} else {
|
||||
p_ctx->status = VC_CONTAINER_NET_ERROR_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
return p_ctx->status;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
vc_container_net_status_t vc_container_net_accept( VC_CONTAINER_NET_T *p_server_ctx, VC_CONTAINER_NET_T **pp_client_ctx )
|
||||
{
|
||||
VC_CONTAINER_NET_T *p_client_ctx = NULL;
|
||||
|
||||
if (!p_server_ctx)
|
||||
return VC_CONTAINER_NET_ERROR_INVALID_SOCKET;
|
||||
|
||||
if (!pp_client_ctx)
|
||||
return VC_CONTAINER_NET_ERROR_INVALID_PARAMETER;
|
||||
|
||||
*pp_client_ctx = NULL;
|
||||
|
||||
if (p_server_ctx->type != STREAM_SERVER)
|
||||
{
|
||||
p_server_ctx->status = VC_CONTAINER_NET_ERROR_NOT_ALLOWED;
|
||||
goto error;
|
||||
}
|
||||
|
||||
p_client_ctx = (VC_CONTAINER_NET_T *)malloc(sizeof(VC_CONTAINER_NET_T));
|
||||
if (!p_client_ctx)
|
||||
{
|
||||
p_server_ctx->status = VC_CONTAINER_NET_ERROR_NO_MEMORY;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Initialise the new context with the address information from the server context */
|
||||
memset(p_client_ctx, 0, sizeof(*p_client_ctx));
|
||||
memcpy(&p_client_ctx->to_addr, &p_server_ctx->to_addr, p_server_ctx->to_addr_len);
|
||||
p_client_ctx->to_addr_len = p_server_ctx->to_addr_len;
|
||||
|
||||
p_client_ctx->socket = accept(p_server_ctx->socket, &p_client_ctx->to_addr.sa, &p_client_ctx->to_addr_len);
|
||||
|
||||
if (p_client_ctx->socket == INVALID_SOCKET)
|
||||
{
|
||||
p_server_ctx->status = vc_container_net_private_last_error();
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Need to bump up the initialisation count, as a new context has been created */
|
||||
p_server_ctx->status = vc_container_net_private_init();
|
||||
if (p_server_ctx->status != VC_CONTAINER_NET_SUCCESS)
|
||||
goto error;
|
||||
|
||||
p_client_ctx->type = STREAM_CLIENT;
|
||||
p_client_ctx->max_datagram_size = vc_container_net_private_maximum_datagram_size(p_client_ctx->socket);
|
||||
p_client_ctx->read_timeout_ms = INFINITE_TIMEOUT_MS;
|
||||
p_client_ctx->status = VC_CONTAINER_NET_SUCCESS;
|
||||
|
||||
*pp_client_ctx = p_client_ctx;
|
||||
return VC_CONTAINER_NET_SUCCESS;
|
||||
|
||||
error:
|
||||
if (p_client_ctx)
|
||||
free(p_client_ctx);
|
||||
return p_server_ctx->status;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
bool vc_container_net_is_data_available( VC_CONTAINER_NET_T *p_ctx )
|
||||
{
|
||||
if (!p_ctx)
|
||||
return false;
|
||||
|
||||
if (p_ctx->type == DATAGRAM_SENDER)
|
||||
{
|
||||
p_ctx->status = VC_CONTAINER_NET_ERROR_NOT_ALLOWED;
|
||||
return false;
|
||||
}
|
||||
|
||||
return socket_wait_for_data(p_ctx, 0);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
size_t vc_container_net_maximum_datagram_size( VC_CONTAINER_NET_T *p_ctx )
|
||||
{
|
||||
return p_ctx ? p_ctx->max_datagram_size : 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static vc_container_net_status_t translate_getnameinfo_error( int error )
|
||||
{
|
||||
switch (error)
|
||||
{
|
||||
case EAI_AGAIN: return VC_CONTAINER_NET_ERROR_TRY_AGAIN;
|
||||
case EAI_FAIL: return VC_CONTAINER_NET_ERROR_HOST_NOT_FOUND;
|
||||
case EAI_MEMORY: return VC_CONTAINER_NET_ERROR_NO_MEMORY;
|
||||
case EAI_NONAME: return VC_CONTAINER_NET_ERROR_HOST_NOT_FOUND;
|
||||
|
||||
/* All other errors are unexpected, so just map to a general purpose error code. */
|
||||
default:
|
||||
return VC_CONTAINER_NET_ERROR_GENERAL;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
vc_container_net_status_t vc_container_net_get_client_name( VC_CONTAINER_NET_T *p_ctx, char *name, size_t name_len )
|
||||
{
|
||||
int result;
|
||||
|
||||
if (!p_ctx)
|
||||
return VC_CONTAINER_NET_ERROR_INVALID_SOCKET;
|
||||
|
||||
if (p_ctx->socket == INVALID_SOCKET)
|
||||
p_ctx->status = VC_CONTAINER_NET_ERROR_NOT_CONNECTED;
|
||||
else if (!name || !name_len)
|
||||
p_ctx->status = VC_CONTAINER_NET_ERROR_INVALID_PARAMETER;
|
||||
else if ((result = getnameinfo(&p_ctx->to_addr.sa, p_ctx->to_addr_len, name, name_len, NULL, 0, 0)) != 0)
|
||||
p_ctx->status = translate_getnameinfo_error(result);
|
||||
else
|
||||
p_ctx->status = VC_CONTAINER_NET_SUCCESS;
|
||||
|
||||
return p_ctx->status;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
vc_container_net_status_t vc_container_net_get_client_port( VC_CONTAINER_NET_T *p_ctx , unsigned short *port )
|
||||
{
|
||||
if (!p_ctx)
|
||||
return VC_CONTAINER_NET_ERROR_INVALID_SOCKET;
|
||||
|
||||
if (p_ctx->socket == INVALID_SOCKET)
|
||||
p_ctx->status = VC_CONTAINER_NET_ERROR_NOT_CONNECTED;
|
||||
else if (!port)
|
||||
p_ctx->status = VC_CONTAINER_NET_ERROR_INVALID_PARAMETER;
|
||||
else
|
||||
{
|
||||
p_ctx->status = VC_CONTAINER_NET_SUCCESS;
|
||||
switch (p_ctx->to_addr.sa.sa_family)
|
||||
{
|
||||
case AF_INET:
|
||||
*port = ntohs(p_ctx->to_addr.in.sin_port);
|
||||
break;
|
||||
case AF_INET6:
|
||||
*port = ntohs(p_ctx->to_addr.in6.sin6_port);
|
||||
break;
|
||||
default:
|
||||
/* Highly unexepcted address family! */
|
||||
p_ctx->status = VC_CONTAINER_NET_ERROR_GENERAL;
|
||||
}
|
||||
}
|
||||
|
||||
return p_ctx->status;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
vc_container_net_status_t vc_container_net_control( VC_CONTAINER_NET_T *p_ctx,
|
||||
vc_container_net_control_t operation,
|
||||
va_list args)
|
||||
{
|
||||
vc_container_net_status_t status;
|
||||
|
||||
switch (operation)
|
||||
{
|
||||
case VC_CONTAINER_NET_CONTROL_SET_READ_BUFFER_SIZE:
|
||||
status = socket_set_read_buffer_size(p_ctx, va_arg(args, uint32_t));
|
||||
break;
|
||||
case VC_CONTAINER_NET_CONTROL_SET_READ_TIMEOUT_MS:
|
||||
status = socket_set_read_timeout_ms(p_ctx, va_arg(args, uint32_t));
|
||||
break;
|
||||
default:
|
||||
status = VC_CONTAINER_NET_ERROR_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
uint32_t vc_container_net_to_host( uint32_t value )
|
||||
{
|
||||
return ntohl(value);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
uint32_t vc_container_net_from_host( uint32_t value )
|
||||
{
|
||||
return htonl(value);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
uint16_t vc_container_net_to_host_16( uint16_t value )
|
||||
{
|
||||
return ntohs(value);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
uint16_t vc_container_net_from_host_16( uint16_t value )
|
||||
{
|
||||
return htons(value);
|
||||
}
|
175
gfx/include/userland/containers/net/net_sockets_null.c
Normal file
175
gfx/include/userland/containers/net/net_sockets_null.c
Normal file
@ -0,0 +1,175 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "net_sockets.h"
|
||||
#include "containers/core/containers_common.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
struct vc_container_net_tag
|
||||
{
|
||||
uint32_t dummy; /* C requires structs not to be empty. */
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_CONTAINER_NET_T *vc_container_net_open( const char *address, const char *port,
|
||||
vc_container_net_open_flags_t flags, vc_container_net_status_t *p_status )
|
||||
{
|
||||
VC_CONTAINER_PARAM_UNUSED(address);
|
||||
VC_CONTAINER_PARAM_UNUSED(port);
|
||||
VC_CONTAINER_PARAM_UNUSED(flags);
|
||||
|
||||
if (p_status)
|
||||
*p_status = VC_CONTAINER_NET_ERROR_NOT_ALLOWED;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
vc_container_net_status_t vc_container_net_close( VC_CONTAINER_NET_T *p_ctx )
|
||||
{
|
||||
VC_CONTAINER_PARAM_UNUSED(p_ctx);
|
||||
|
||||
return VC_CONTAINER_NET_ERROR_INVALID_SOCKET;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
vc_container_net_status_t vc_container_net_status( VC_CONTAINER_NET_T *p_ctx )
|
||||
{
|
||||
VC_CONTAINER_PARAM_UNUSED(p_ctx);
|
||||
|
||||
return VC_CONTAINER_NET_ERROR_INVALID_SOCKET;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
size_t vc_container_net_read( VC_CONTAINER_NET_T *p_ctx, void *buffer, size_t size )
|
||||
{
|
||||
VC_CONTAINER_PARAM_UNUSED(p_ctx);
|
||||
VC_CONTAINER_PARAM_UNUSED(buffer);
|
||||
VC_CONTAINER_PARAM_UNUSED(size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
size_t vc_container_net_write( VC_CONTAINER_NET_T *p_ctx, const void *buffer, size_t size )
|
||||
{
|
||||
VC_CONTAINER_PARAM_UNUSED(p_ctx);
|
||||
VC_CONTAINER_PARAM_UNUSED(buffer);
|
||||
VC_CONTAINER_PARAM_UNUSED(size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
vc_container_net_status_t vc_container_net_listen( VC_CONTAINER_NET_T *p_ctx, uint32_t maximum_connections )
|
||||
{
|
||||
VC_CONTAINER_PARAM_UNUSED(p_ctx);
|
||||
VC_CONTAINER_PARAM_UNUSED(maximum_connections);
|
||||
|
||||
return VC_CONTAINER_NET_ERROR_INVALID_SOCKET;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
vc_container_net_status_t vc_container_net_accept( VC_CONTAINER_NET_T *p_server_ctx, VC_CONTAINER_NET_T **pp_client_ctx )
|
||||
{
|
||||
VC_CONTAINER_PARAM_UNUSED(p_server_ctx);
|
||||
VC_CONTAINER_PARAM_UNUSED(pp_client_ctx);
|
||||
|
||||
return VC_CONTAINER_NET_ERROR_INVALID_SOCKET;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
bool vc_container_net_is_data_available( VC_CONTAINER_NET_T *p_ctx )
|
||||
{
|
||||
VC_CONTAINER_PARAM_UNUSED(p_ctx);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
size_t vc_container_net_maximum_datagram_size( VC_CONTAINER_NET_T *p_ctx )
|
||||
{
|
||||
VC_CONTAINER_PARAM_UNUSED(p_ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
vc_container_net_status_t vc_container_net_get_client_name( VC_CONTAINER_NET_T *p_ctx, char *name, size_t name_len )
|
||||
{
|
||||
VC_CONTAINER_PARAM_UNUSED(p_ctx);
|
||||
VC_CONTAINER_PARAM_UNUSED(name);
|
||||
VC_CONTAINER_PARAM_UNUSED(name_len);
|
||||
|
||||
return VC_CONTAINER_NET_ERROR_INVALID_SOCKET;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
vc_container_net_status_t vc_container_net_get_client_port( VC_CONTAINER_NET_T *p_ctx , unsigned short *port )
|
||||
{
|
||||
VC_CONTAINER_PARAM_UNUSED(p_ctx);
|
||||
VC_CONTAINER_PARAM_UNUSED(port);
|
||||
|
||||
return VC_CONTAINER_NET_ERROR_INVALID_SOCKET;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
vc_container_net_status_t vc_container_net_control( VC_CONTAINER_NET_T *p_ctx,
|
||||
vc_container_net_control_t operation,
|
||||
va_list args)
|
||||
{
|
||||
VC_CONTAINER_PARAM_UNUSED(p_ctx);
|
||||
VC_CONTAINER_PARAM_UNUSED(operation);
|
||||
VC_CONTAINER_PARAM_UNUSED(args);
|
||||
|
||||
return VC_CONTAINER_NET_ERROR_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
uint32_t vc_container_net_to_host( uint32_t value )
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
uint32_t vc_container_net_from_host( uint32_t value )
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
uint16_t vc_container_net_to_host_16( uint16_t value )
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
uint16_t vc_container_net_from_host_16( uint16_t value )
|
||||
{
|
||||
return value;
|
||||
}
|
85
gfx/include/userland/containers/net/net_sockets_priv.h
Normal file
85
gfx/include/userland/containers/net/net_sockets_priv.h
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _NET_SOCKETS_PRIV_H_
|
||||
#define _NET_SOCKETS_PRIV_H_
|
||||
|
||||
#include "net_sockets.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#include "net_sockets_win32.h"
|
||||
#else
|
||||
#include "net_sockets_bsd.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum
|
||||
{
|
||||
STREAM_CLIENT = 0, /**< TCP client */
|
||||
STREAM_SERVER, /**< TCP server */
|
||||
DATAGRAM_SENDER, /**< UDP sender */
|
||||
DATAGRAM_RECEIVER /**< UDP receiver */
|
||||
} vc_container_net_type_t;
|
||||
|
||||
|
||||
/** Perform implementation-specific per-socket initialization.
|
||||
*
|
||||
* \return VC_CONTAINER_NET_SUCCESS or one of the error codes on failure. */
|
||||
vc_container_net_status_t vc_container_net_private_init( void );
|
||||
|
||||
/** Perform implementation-specific per-socket deinitialization.
|
||||
* This function is always called once for each successful call to socket_private_init(). */
|
||||
void vc_container_net_private_deinit( void );
|
||||
|
||||
/** Return the last error from the socket implementation. */
|
||||
vc_container_net_status_t vc_container_net_private_last_error( void );
|
||||
|
||||
/** Implementation-specific internal socket close.
|
||||
*
|
||||
* \param sock Internal socket to be closed. */
|
||||
void vc_container_net_private_close( SOCKET_T sock );
|
||||
|
||||
/** Enable or disable socket address reusability.
|
||||
*
|
||||
* \param sock Internal socket to be closed.
|
||||
* \param enable True to enable reusability, false to clear it. */
|
||||
void vc_container_net_private_set_reusable( SOCKET_T sock, bool enable );
|
||||
|
||||
/** Query the maximum datagram size for the socket.
|
||||
*
|
||||
* \param sock The socket to query.
|
||||
* \return The maximum supported datagram size on the socket. */
|
||||
size_t vc_container_net_private_maximum_datagram_size( SOCKET_T sock );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _NET_SOCKETS_PRIV_H_ */
|
140
gfx/include/userland/containers/net/net_sockets_win32.c
Normal file
140
gfx/include/userland/containers/net/net_sockets_win32.c
Normal file
@ -0,0 +1,140 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "net_sockets.h"
|
||||
#include "net_sockets_priv.h"
|
||||
#include "containers/core/containers_common.h"
|
||||
|
||||
#pragma comment(lib, "Ws2_32.lib")
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Default maximum datagram size.
|
||||
* This is based on the default Ethernet MTU size, less the IP and UDP headers.
|
||||
*/
|
||||
#define DEFAULT_MAXIMUM_DATAGRAM_SIZE (1500 - 20 - 8)
|
||||
|
||||
/** Maximum socket buffer size to use. */
|
||||
#define MAXIMUM_BUFFER_SIZE 65536
|
||||
|
||||
/*****************************************************************************/
|
||||
static vc_container_net_status_t translate_error_status( int error )
|
||||
{
|
||||
switch (error)
|
||||
{
|
||||
case WSA_INVALID_HANDLE: return VC_CONTAINER_NET_ERROR_INVALID_SOCKET;
|
||||
case WSA_NOT_ENOUGH_MEMORY: return VC_CONTAINER_NET_ERROR_NO_MEMORY;
|
||||
case WSA_INVALID_PARAMETER: return VC_CONTAINER_NET_ERROR_INVALID_PARAMETER;
|
||||
case WSAEACCES: return VC_CONTAINER_NET_ERROR_ACCESS_DENIED;
|
||||
case WSAEFAULT: return VC_CONTAINER_NET_ERROR_INVALID_PARAMETER;
|
||||
case WSAEINVAL: return VC_CONTAINER_NET_ERROR_INVALID_PARAMETER;
|
||||
case WSAEMFILE: return VC_CONTAINER_NET_ERROR_TOO_BIG;
|
||||
case WSAEWOULDBLOCK: return VC_CONTAINER_NET_ERROR_WOULD_BLOCK;
|
||||
case WSAEINPROGRESS: return VC_CONTAINER_NET_ERROR_IN_PROGRESS;
|
||||
case WSAEALREADY: return VC_CONTAINER_NET_ERROR_IN_PROGRESS;
|
||||
case WSAEADDRINUSE: return VC_CONTAINER_NET_ERROR_IN_USE;
|
||||
case WSAEADDRNOTAVAIL: return VC_CONTAINER_NET_ERROR_INVALID_PARAMETER;
|
||||
case WSAENETDOWN: return VC_CONTAINER_NET_ERROR_NETWORK;
|
||||
case WSAENETUNREACH: return VC_CONTAINER_NET_ERROR_NETWORK;
|
||||
case WSAENETRESET: return VC_CONTAINER_NET_ERROR_CONNECTION_LOST;
|
||||
case WSAECONNABORTED: return VC_CONTAINER_NET_ERROR_CONNECTION_LOST;
|
||||
case WSAECONNRESET: return VC_CONTAINER_NET_ERROR_CONNECTION_LOST;
|
||||
case WSAENOBUFS: return VC_CONTAINER_NET_ERROR_NO_MEMORY;
|
||||
case WSAENOTCONN: return VC_CONTAINER_NET_ERROR_NOT_CONNECTED;
|
||||
case WSAESHUTDOWN: return VC_CONTAINER_NET_ERROR_CONNECTION_LOST;
|
||||
case WSAETIMEDOUT: return VC_CONTAINER_NET_ERROR_TIMED_OUT;
|
||||
case WSAECONNREFUSED: return VC_CONTAINER_NET_ERROR_CONNECTION_REFUSED;
|
||||
case WSAELOOP: return VC_CONTAINER_NET_ERROR_INVALID_PARAMETER;
|
||||
case WSAENAMETOOLONG: return VC_CONTAINER_NET_ERROR_INVALID_PARAMETER;
|
||||
case WSAEHOSTDOWN: return VC_CONTAINER_NET_ERROR_NETWORK;
|
||||
case WSAEHOSTUNREACH: return VC_CONTAINER_NET_ERROR_NETWORK;
|
||||
case WSAEPROCLIM: return VC_CONTAINER_NET_ERROR_NO_MEMORY;
|
||||
case WSAEUSERS: return VC_CONTAINER_NET_ERROR_NO_MEMORY;
|
||||
case WSAEDQUOT: return VC_CONTAINER_NET_ERROR_NO_MEMORY;
|
||||
case WSAESTALE: return VC_CONTAINER_NET_ERROR_INVALID_SOCKET;
|
||||
case WSAEDISCON: return VC_CONTAINER_NET_ERROR_CONNECTION_LOST;
|
||||
case WSAHOST_NOT_FOUND: return VC_CONTAINER_NET_ERROR_HOST_NOT_FOUND;
|
||||
case WSATRY_AGAIN: return VC_CONTAINER_NET_ERROR_TRY_AGAIN;
|
||||
case WSANO_RECOVERY: return VC_CONTAINER_NET_ERROR_HOST_NOT_FOUND;
|
||||
case WSANO_DATA: return VC_CONTAINER_NET_ERROR_HOST_NOT_FOUND;
|
||||
|
||||
/* All other errors are unexpected, so just map to a general purpose error code. */
|
||||
default:
|
||||
return VC_CONTAINER_NET_ERROR_GENERAL;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
vc_container_net_status_t vc_container_net_private_last_error()
|
||||
{
|
||||
return translate_error_status( WSAGetLastError() );
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
vc_container_net_status_t vc_container_net_private_init()
|
||||
{
|
||||
WSADATA wsa_data;
|
||||
int result;
|
||||
|
||||
result = WSAStartup(MAKEWORD(2,2), &wsa_data);
|
||||
if (result)
|
||||
return translate_error_status( result );
|
||||
|
||||
return VC_CONTAINER_NET_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
void vc_container_net_private_deinit()
|
||||
{
|
||||
WSACleanup();
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
void vc_container_net_private_close( SOCKET_T sock )
|
||||
{
|
||||
closesocket(sock);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
void vc_container_net_private_set_reusable( SOCKET_T sock, bool enable )
|
||||
{
|
||||
BOOL opt = enable ? TRUE : FALSE;
|
||||
|
||||
(void)setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof(opt));
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
size_t vc_container_net_private_maximum_datagram_size( SOCKET_T sock )
|
||||
{
|
||||
size_t max_datagram_size = DEFAULT_MAXIMUM_DATAGRAM_SIZE;
|
||||
int opt_size = sizeof(max_datagram_size);
|
||||
|
||||
/* Ignore errors and use the default if necessary */
|
||||
(void)getsockopt(sock, SOL_SOCKET, SO_MAX_MSG_SIZE, (char *)&max_datagram_size, &opt_size);
|
||||
|
||||
return max_datagram_size;
|
||||
}
|
38
gfx/include/userland/containers/net/net_sockets_win32.h
Normal file
38
gfx/include/userland/containers/net/net_sockets_win32.h
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _NET_SOCKETS_WIN32_H_
|
||||
#define _NET_SOCKETS_WIN32_H_
|
||||
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
|
||||
typedef SOCKET SOCKET_T;
|
||||
typedef int SOCKADDR_LEN_T;
|
||||
typedef char *SOCKOPT_CAST_T;
|
||||
|
||||
#endif /* _NET_SOCKETS_WIN32_H_ */
|
159
gfx/include/userland/containers/packetizers.h
Normal file
159
gfx/include/userland/containers/packetizers.h
Normal file
@ -0,0 +1,159 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef VC_PACKETIZERS_H
|
||||
#define VC_PACKETIZERS_H
|
||||
|
||||
/** \file packetizers.h
|
||||
* Public API for packetizing data (i.e. framing and timestamping)
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "containers/containers.h"
|
||||
|
||||
/** \defgroup VcPacketizerApi Packetizer API
|
||||
* API for packetizers */
|
||||
/* @{ */
|
||||
|
||||
/** \name Packetizer flags
|
||||
* \anchor packetizerflags
|
||||
* The following flags describe properties of a packetizer */
|
||||
/* @{ */
|
||||
#define VC_PACKETIZER_FLAG_ES_CHANGED 0x1 /**< ES definition has changed */
|
||||
/* @} */
|
||||
|
||||
/** Definition of the packetizer type */
|
||||
typedef struct VC_PACKETIZER_T
|
||||
{
|
||||
struct VC_PACKETIZER_PRIVATE_T *priv; /**< Private member used by the implementation */
|
||||
uint32_t flags; /**< Flags describing the properties of a packetizer.
|
||||
* See \ref packetizerflags "Packetizer flags". */
|
||||
|
||||
VC_CONTAINER_ES_FORMAT_T *in; /**< Format of the input elementary stream */
|
||||
VC_CONTAINER_ES_FORMAT_T *out; /**< Format of the output elementary stream */
|
||||
|
||||
uint32_t max_frame_size; /**< Maximum size of a packetized frame */
|
||||
|
||||
} VC_PACKETIZER_T;
|
||||
|
||||
/** Open a packetizer to convert the input format into the requested output format.
|
||||
* This will create an an instance of a packetizer and its associated context.
|
||||
*
|
||||
* If no packetizer is found for the requested format, this will return a null pointer as well as
|
||||
* an error code indicating why this failed.
|
||||
*
|
||||
* \param in Input elementary stream format
|
||||
* \param out_variant Requested output variant for the output elementary stream format
|
||||
* \param status Returns the status of the operation
|
||||
* \return A pointer to the context of the new instance of the packetizer.
|
||||
* Returns NULL on failure.
|
||||
*/
|
||||
VC_PACKETIZER_T *vc_packetizer_open(VC_CONTAINER_ES_FORMAT_T *in, VC_CONTAINER_FOURCC_T out_variant,
|
||||
VC_CONTAINER_STATUS_T *status);
|
||||
|
||||
/** Closes an instance of a packetizer.
|
||||
* This will free all the resources associated with the context.
|
||||
*
|
||||
* \param context Pointer to the context of the instance to close
|
||||
* \return the status of the operation
|
||||
*/
|
||||
VC_CONTAINER_STATUS_T vc_packetizer_close( VC_PACKETIZER_T *context );
|
||||
|
||||
/** \name Packetizer flags
|
||||
* The following flags can be passed during a packetize call */
|
||||
/* @{ */
|
||||
/** Type definition for the packetizer flags */
|
||||
typedef uint32_t VC_PACKETIZER_FLAGS_T;
|
||||
/** Ask the packetizer to only return information on the next packet without reading it */
|
||||
#define VC_PACKETIZER_FLAG_INFO 0x1
|
||||
/** Ask the packetizer to skip the next packet */
|
||||
#define VC_PACKETIZER_FLAG_SKIP 0x2
|
||||
/** Ask the packetizer to flush any data being processed */
|
||||
#define VC_PACKETIZER_FLAG_FLUSH 0x4
|
||||
/** Force the packetizer to release an input packet */
|
||||
#define VC_PACKETIZER_FLAG_FORCE_RELEASE_INPUT 0x8
|
||||
/* @} */
|
||||
|
||||
/** Push a new packet of data to the packetizer.
|
||||
* This is the mechanism used to feed data into the packetizer. Once a packet has been
|
||||
* pushed into the packetizer it is owned by the packetizer until released by a call to
|
||||
* \ref vc_packetizer_pop
|
||||
*
|
||||
* \param context Pointer to the context of the packetizer to use
|
||||
* \param packet Pointer to the VC_CONTAINER_PACKET_T structure describing the data packet
|
||||
* to push into the packetizer.
|
||||
* \return the status of the operation
|
||||
*/
|
||||
VC_CONTAINER_STATUS_T vc_packetizer_push( VC_PACKETIZER_T *context,
|
||||
VC_CONTAINER_PACKET_T *packet);
|
||||
|
||||
/** Pop a packet of data from the packetizer.
|
||||
* This allows the client to retrieve consumed data from the packetizer. Packets returned by
|
||||
* the packetizer in this manner can then be released / recycled by the client.
|
||||
* It is possible for the client to retrieve non-consumed data by passing the
|
||||
* VC_PACKETIZER_FLAG_FORCE_RELEASE_INPUT flag. This will however trigger some internal buffering
|
||||
* inside the packetizer and thus is less efficient.
|
||||
*
|
||||
* \param context Pointer to the context of the packetizer to use
|
||||
* \param packet Pointer used to return a consumed packet
|
||||
* \param flags Miscellaneous flags controlling the operation
|
||||
*
|
||||
* \return VC_CONTAINER_SUCCESS if a consumed packet was retrieved,
|
||||
* VC_CONTAINER_ERROR_INCOMPLETE_DATA if none is available.
|
||||
*/
|
||||
VC_CONTAINER_STATUS_T vc_packetizer_pop( VC_PACKETIZER_T *context,
|
||||
VC_CONTAINER_PACKET_T **packet, VC_PACKETIZER_FLAGS_T flags);
|
||||
|
||||
/** Read packetized data out of the packetizer.
|
||||
*
|
||||
* \param context Pointer to the context of the packetizer to use
|
||||
* \param packet Pointer to the VC_CONTAINER_PACKET_T structure describing the data packet
|
||||
* This might need to be partially filled before the call (buffer, buffer_size)
|
||||
* depending on the flags used.
|
||||
* \param flags Miscellaneous flags controlling the operation
|
||||
* \return the status of the operation
|
||||
*/
|
||||
VC_CONTAINER_STATUS_T vc_packetizer_read( VC_PACKETIZER_T *context,
|
||||
VC_CONTAINER_PACKET_T *out, VC_PACKETIZER_FLAGS_T flags);
|
||||
|
||||
/** Reset packetizer state.
|
||||
* This will reset the state of the packetizer as well as mark all data pushed to it as consumed.
|
||||
*
|
||||
* \param context Pointer to the context of the packetizer to reset
|
||||
* \return the status of the operation
|
||||
*/
|
||||
VC_CONTAINER_STATUS_T vc_packetizer_reset( VC_PACKETIZER_T *context );
|
||||
|
||||
/* @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* VC_PACKETIZERS_H */
|
269
gfx/include/userland/containers/pcm/pcm_packetizer.c
Normal file
269
gfx/include/userland/containers/pcm/pcm_packetizer.c
Normal file
@ -0,0 +1,269 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* Implementation of a PCM packetizer.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "containers/packetizers.h"
|
||||
#include "containers/core/packetizers_private.h"
|
||||
#include "containers/core/containers_common.h"
|
||||
#include "containers/core/containers_logging.h"
|
||||
#include "containers/core/containers_time.h"
|
||||
#include "containers/core/containers_utils.h"
|
||||
#include "containers/core/containers_bytestream.h"
|
||||
|
||||
#define FRAME_SIZE (16*1024) /**< Arbitrary value which is neither too small nor too big */
|
||||
#define FACTOR_SHIFT 4 /**< Shift applied to the conversion factor */
|
||||
|
||||
VC_CONTAINER_STATUS_T pcm_packetizer_open( VC_PACKETIZER_T * );
|
||||
|
||||
/*****************************************************************************/
|
||||
enum conversion {
|
||||
CONVERSION_NONE = 0,
|
||||
CONVERSION_U8_TO_S16L,
|
||||
CONVERSION_UNKNOWN
|
||||
};
|
||||
|
||||
typedef struct VC_PACKETIZER_MODULE_T {
|
||||
enum {
|
||||
STATE_NEW_PACKET = 0,
|
||||
STATE_DATA
|
||||
} state;
|
||||
|
||||
unsigned int samples_per_frame;
|
||||
unsigned int bytes_per_sample;
|
||||
unsigned int max_frame_size;
|
||||
|
||||
uint32_t bytes_read;
|
||||
unsigned int frame_size;
|
||||
|
||||
enum conversion conversion;
|
||||
unsigned int conversion_factor;
|
||||
} VC_PACKETIZER_MODULE_T;
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T pcm_packetizer_close( VC_PACKETIZER_T *p_ctx )
|
||||
{
|
||||
free(p_ctx->priv->module);
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T pcm_packetizer_reset( VC_PACKETIZER_T *p_ctx )
|
||||
{
|
||||
VC_PACKETIZER_MODULE_T *module = p_ctx->priv->module;
|
||||
module->state = STATE_NEW_PACKET;
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static void convert_pcm_u8_to_s16l( uint8_t **p_out, uint8_t *in, size_t size)
|
||||
{
|
||||
int16_t *out = (int16_t *)*p_out;
|
||||
uint8_t tmp;
|
||||
|
||||
while(size--)
|
||||
{
|
||||
tmp = *in++;
|
||||
*out++ = ((tmp - 128) << 8) | tmp;
|
||||
}
|
||||
*p_out = (uint8_t *)out;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static void convert_pcm( VC_PACKETIZER_T *p_ctx,
|
||||
VC_CONTAINER_BYTESTREAM_T *stream, size_t size, uint8_t *out )
|
||||
{
|
||||
VC_PACKETIZER_MODULE_T *module = p_ctx->priv->module;
|
||||
uint8_t tmp[256];
|
||||
size_t tmp_size;
|
||||
|
||||
while(size)
|
||||
{
|
||||
tmp_size = MIN(sizeof(tmp), size);
|
||||
bytestream_get(stream, tmp, tmp_size);
|
||||
if (module->conversion == CONVERSION_U8_TO_S16L)
|
||||
convert_pcm_u8_to_s16l(&out, tmp, tmp_size);
|
||||
else
|
||||
bytestream_skip(stream, tmp_size);
|
||||
size -= tmp_size;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T pcm_packetizer_packetize( VC_PACKETIZER_T *p_ctx,
|
||||
VC_CONTAINER_PACKET_T *out, VC_PACKETIZER_FLAGS_T flags )
|
||||
{
|
||||
VC_PACKETIZER_MODULE_T *module = p_ctx->priv->module;
|
||||
VC_CONTAINER_BYTESTREAM_T *stream = &p_ctx->priv->stream;
|
||||
VC_CONTAINER_TIME_T *time = &p_ctx->priv->time;
|
||||
int64_t pts, dts;
|
||||
size_t offset, size;
|
||||
|
||||
while(1) switch (module->state)
|
||||
{
|
||||
case STATE_NEW_PACKET:
|
||||
/* Make sure we've got enough data */
|
||||
if(bytestream_size(stream) < module->max_frame_size &&
|
||||
!(flags & VC_PACKETIZER_FLAG_FLUSH))
|
||||
return VC_CONTAINER_ERROR_INCOMPLETE_DATA;
|
||||
if(!bytestream_size(stream))
|
||||
return VC_CONTAINER_ERROR_INCOMPLETE_DATA;
|
||||
|
||||
module->frame_size = bytestream_size(stream);
|
||||
if(module->frame_size > module->max_frame_size)
|
||||
module->frame_size = module->max_frame_size;
|
||||
bytestream_get_timestamps_and_offset(stream, &pts, &dts, &offset, true);
|
||||
vc_container_time_set(time, pts);
|
||||
if(pts != VC_CONTAINER_TIME_UNKNOWN)
|
||||
vc_container_time_add(time, offset / module->bytes_per_sample);
|
||||
|
||||
module->bytes_read = 0;
|
||||
module->state = STATE_DATA;
|
||||
/* fall through to the next state */
|
||||
|
||||
case STATE_DATA:
|
||||
size = module->frame_size - module->bytes_read;
|
||||
out->pts = out->dts = VC_CONTAINER_TIME_UNKNOWN;
|
||||
out->flags = VC_CONTAINER_PACKET_FLAG_FRAME_END;
|
||||
out->size = (size * module->conversion_factor) >> FACTOR_SHIFT;
|
||||
|
||||
if(!module->bytes_read)
|
||||
{
|
||||
out->pts = out->dts = vc_container_time_get(time);
|
||||
out->flags |= VC_CONTAINER_PACKET_FLAG_FRAME_START;
|
||||
}
|
||||
|
||||
if(flags & VC_PACKETIZER_FLAG_INFO)
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
|
||||
if(flags & VC_PACKETIZER_FLAG_SKIP)
|
||||
{
|
||||
bytestream_skip( stream, size );
|
||||
}
|
||||
else
|
||||
{
|
||||
out->size = MIN(out->size, out->buffer_size);
|
||||
size = (out->size << FACTOR_SHIFT) / module->conversion_factor;
|
||||
out->size = (size * module->conversion_factor) >> FACTOR_SHIFT;
|
||||
|
||||
if(module->conversion != CONVERSION_NONE)
|
||||
convert_pcm(p_ctx, stream, size, out->data);
|
||||
else
|
||||
bytestream_get(stream, out->data, out->size);
|
||||
}
|
||||
module->bytes_read += size;
|
||||
|
||||
if(module->bytes_read == module->frame_size)
|
||||
{
|
||||
vc_container_time_add(time, module->samples_per_frame);
|
||||
module->state = STATE_NEW_PACKET;
|
||||
}
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
|
||||
default:
|
||||
break;
|
||||
};
|
||||
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_CONTAINER_STATUS_T pcm_packetizer_open( VC_PACKETIZER_T *p_ctx )
|
||||
{
|
||||
VC_PACKETIZER_MODULE_T *module;
|
||||
unsigned int bytes_per_sample = 0;
|
||||
enum conversion conversion = CONVERSION_NONE;
|
||||
|
||||
if(p_ctx->in->codec != VC_CONTAINER_CODEC_PCM_UNSIGNED_BE &&
|
||||
p_ctx->in->codec != VC_CONTAINER_CODEC_PCM_UNSIGNED_LE &&
|
||||
p_ctx->in->codec != VC_CONTAINER_CODEC_PCM_SIGNED_BE &&
|
||||
p_ctx->in->codec != VC_CONTAINER_CODEC_PCM_SIGNED_LE &&
|
||||
p_ctx->in->codec != VC_CONTAINER_CODEC_PCM_FLOAT_BE &&
|
||||
p_ctx->in->codec != VC_CONTAINER_CODEC_PCM_FLOAT_LE)
|
||||
return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
|
||||
if(p_ctx->in->type->audio.block_align)
|
||||
bytes_per_sample = p_ctx->in->type->audio.block_align;
|
||||
else if(p_ctx->in->type->audio.bits_per_sample && p_ctx->in->type->audio.channels)
|
||||
bytes_per_sample = p_ctx->in->type->audio.bits_per_sample *
|
||||
p_ctx->in->type->audio.channels / 8;
|
||||
|
||||
if(!bytes_per_sample)
|
||||
return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
|
||||
/* Check if we support any potential conversion we've been asked to do */
|
||||
if(p_ctx->out->codec_variant)
|
||||
conversion = CONVERSION_UNKNOWN;
|
||||
if(p_ctx->out->codec_variant == VC_FOURCC('s','1','6','l') &&
|
||||
p_ctx->in->codec == VC_CONTAINER_CODEC_PCM_SIGNED_LE &&
|
||||
p_ctx->in->type->audio.bits_per_sample == 16)
|
||||
conversion = CONVERSION_NONE;
|
||||
if(p_ctx->out->codec_variant == VC_FOURCC('s','1','6','l') &&
|
||||
(p_ctx->in->codec == VC_CONTAINER_CODEC_PCM_UNSIGNED_LE ||
|
||||
p_ctx->in->codec == VC_CONTAINER_CODEC_PCM_UNSIGNED_BE) &&
|
||||
p_ctx->in->type->audio.bits_per_sample == 8)
|
||||
conversion = CONVERSION_U8_TO_S16L;
|
||||
if(conversion == CONVERSION_UNKNOWN)
|
||||
return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
|
||||
p_ctx->priv->module = module = malloc(sizeof(*module));
|
||||
if(!module)
|
||||
return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
|
||||
memset(module, 0, sizeof(*module));
|
||||
module->conversion = conversion;
|
||||
module->conversion_factor = 1 << FACTOR_SHIFT;
|
||||
|
||||
p_ctx->out->codec_variant = 0;
|
||||
if(conversion == CONVERSION_U8_TO_S16L)
|
||||
{
|
||||
module->conversion_factor = 2 << FACTOR_SHIFT;
|
||||
p_ctx->out->type->audio.bits_per_sample *= 2;
|
||||
p_ctx->out->type->audio.block_align *= 2;
|
||||
p_ctx->out->codec = VC_CONTAINER_CODEC_PCM_SIGNED_LE;
|
||||
}
|
||||
|
||||
vc_container_time_set_samplerate(&p_ctx->priv->time, p_ctx->in->type->audio.sample_rate, 1);
|
||||
|
||||
p_ctx->max_frame_size = FRAME_SIZE;
|
||||
module->max_frame_size = (FRAME_SIZE << FACTOR_SHIFT) / module->conversion_factor;
|
||||
module->bytes_per_sample = bytes_per_sample;
|
||||
module->samples_per_frame = module->max_frame_size / bytes_per_sample;
|
||||
p_ctx->priv->pf_close = pcm_packetizer_close;
|
||||
p_ctx->priv->pf_packetize = pcm_packetizer_packetize;
|
||||
p_ctx->priv->pf_reset = pcm_packetizer_reset;
|
||||
|
||||
LOG_DEBUG(0, "using pcm audio packetizer");
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_PACKETIZER_REGISTER(pcm_packetizer_open, "pcm");
|
13
gfx/include/userland/containers/qsynth/CMakeLists.txt
Normal file
13
gfx/include/userland/containers/qsynth/CMakeLists.txt
Normal file
@ -0,0 +1,13 @@
|
||||
# Container module needs to go in as a plugins so different prefix
|
||||
# and install path
|
||||
set(CMAKE_SHARED_LIBRARY_PREFIX "")
|
||||
|
||||
# Make sure the compiler can find the necessary include files
|
||||
include_directories (../..)
|
||||
|
||||
add_library(reader_qsynth ${LIBRARY_TYPE} qsynth_reader.c)
|
||||
|
||||
target_link_libraries(reader_qsynth containers)
|
||||
|
||||
install(TARGETS reader_qsynth DESTINATION ${VMCS_PLUGIN_DIR})
|
||||
|
482
gfx/include/userland/containers/qsynth/qsynth_reader.c
Normal file
482
gfx/include/userland/containers/qsynth/qsynth_reader.c
Normal file
@ -0,0 +1,482 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "containers/core/containers_private.h"
|
||||
#include "containers/core/containers_io_helpers.h"
|
||||
#include "containers/core/containers_utils.h"
|
||||
#include "containers/core/containers_logging.h"
|
||||
|
||||
/******************************************************************************
|
||||
Defines.
|
||||
******************************************************************************/
|
||||
|
||||
#define BI32(b) (((b)[0]<<24)|((b)[1]<<16)|((b)[2]<<8)|((b)[3]))
|
||||
#define BI16(b) (((b)[0]<<8)|((b)[1]))
|
||||
|
||||
#define HEADER_LENGTH 14
|
||||
#define MAX_TRACKS 128
|
||||
|
||||
/******************************************************************************
|
||||
Type definitions
|
||||
******************************************************************************/
|
||||
struct _QSYNTH_SEGMENT_T {
|
||||
struct _QSYNTH_SEGMENT_T *next;
|
||||
uint32_t len;
|
||||
uint8_t *data;
|
||||
};
|
||||
typedef struct _QSYNTH_SEGMENT_T QSYNTH_SEGMENT_T;
|
||||
|
||||
typedef struct VC_CONTAINER_MODULE_T
|
||||
{
|
||||
VC_CONTAINER_TRACK_T *track;
|
||||
uint32_t filesize;
|
||||
QSYNTH_SEGMENT_T *seg;
|
||||
QSYNTH_SEGMENT_T *pass;
|
||||
uint32_t sent;
|
||||
int64_t timestamp;
|
||||
uint32_t seek;
|
||||
} VC_CONTAINER_MODULE_T;
|
||||
|
||||
/******************************************************************************
|
||||
Function prototypes
|
||||
******************************************************************************/
|
||||
VC_CONTAINER_STATUS_T qsynth_reader_open( VC_CONTAINER_T * );
|
||||
|
||||
/******************************************************************************
|
||||
Local Functions
|
||||
******************************************************************************/
|
||||
|
||||
static VC_CONTAINER_STATUS_T qsynth_read_header(uint8_t *data, uint32_t *tracks,
|
||||
uint32_t *division, uint8_t *fps, uint8_t *dpf)
|
||||
{
|
||||
if(data[0] != 'M' || data[1] != 'T' || data[2] != 'h' || data[3] != 'd' ||
|
||||
data[4] != 0 || data[5] != 0 || data[6] != 0 || data[7] != 6)
|
||||
return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
|
||||
if(data[12] < 0x80)
|
||||
{
|
||||
if(division) *division = BI16(data+12);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(fps) *fps = 256-data[12];
|
||||
if(dpf) *dpf = data[13];
|
||||
}
|
||||
|
||||
if(tracks) *tracks = BI16(data+10);
|
||||
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
static int qsynth_read_variable(uint8_t *data, uint32_t *val)
|
||||
{
|
||||
int i = 0;
|
||||
*val = 0;
|
||||
do {
|
||||
*val = (*val << 7) + (data[i] & 0x7f);
|
||||
} while(data[i++] & 0x80);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static VC_CONTAINER_STATUS_T qsynth_read_event(uint8_t *data, uint32_t *used, uint8_t *last,
|
||||
uint32_t *time, uint32_t *tempo, uint32_t *end)
|
||||
{
|
||||
int read;
|
||||
|
||||
// need at least 4 bytes here
|
||||
read = qsynth_read_variable(data, time);
|
||||
|
||||
if(data[read] == 0xff) // meta event
|
||||
{
|
||||
uint32_t len;
|
||||
uint8_t type = data[read+1];
|
||||
|
||||
read += 2;
|
||||
read += qsynth_read_variable(data+read, &len);
|
||||
|
||||
if(type == 0x2f) // end of track
|
||||
{
|
||||
if(len != 0)
|
||||
return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
|
||||
*end = 1;
|
||||
}
|
||||
else if(type == 0x51) // tempo event
|
||||
{
|
||||
if(len != 3)
|
||||
return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
|
||||
*tempo = (data[read]<<16) | (data[read+1]<<8) | data[read+2];
|
||||
}
|
||||
|
||||
read += len;
|
||||
}
|
||||
else if(data[read] == 0xf0 || data[read] == 0xf7) // sysex events
|
||||
{
|
||||
uint32_t len;
|
||||
read += 1;
|
||||
read += qsynth_read_variable(data+read, &len) + len;
|
||||
}
|
||||
else // midi event
|
||||
{
|
||||
uint8_t type;
|
||||
|
||||
if(data[read] < 128)
|
||||
type = *last;
|
||||
else
|
||||
{
|
||||
type = data[read] >> 4;
|
||||
*last = type;
|
||||
read++;
|
||||
}
|
||||
|
||||
switch(type) {
|
||||
case 8: case 9: case 0xa: case 0xb: case 0xe:
|
||||
read += 2;
|
||||
break;
|
||||
case 0xc: case 0xd:
|
||||
read += 1;
|
||||
break;
|
||||
default:
|
||||
return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
}
|
||||
}
|
||||
|
||||
*used = read;
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
static VC_CONTAINER_STATUS_T qsynth_read_track(QSYNTH_SEGMENT_T *seg,
|
||||
uint32_t *ticks, int64_t *time,
|
||||
uint32_t *us_perclock, uint32_t *tempo_ticks)
|
||||
{
|
||||
uint32_t total_ticks = 0;
|
||||
uint32_t used = 8;
|
||||
uint8_t last = 0;
|
||||
|
||||
*time = 0LL;
|
||||
*tempo_ticks = 0;
|
||||
|
||||
while(used < seg->len)
|
||||
{
|
||||
VC_CONTAINER_STATUS_T status;
|
||||
uint32_t event_ticks, new_tempo = 0, end = 0, event_used;
|
||||
if((status = qsynth_read_event(seg->data+used, &event_used, &last, &event_ticks, &new_tempo, &end)) != VC_CONTAINER_SUCCESS)
|
||||
return status;
|
||||
|
||||
used += event_used;
|
||||
total_ticks += event_ticks;
|
||||
|
||||
if(new_tempo != 0)
|
||||
{
|
||||
*time += ((int64_t) (total_ticks - *tempo_ticks)) * (*us_perclock);
|
||||
*us_perclock = new_tempo;
|
||||
*tempo_ticks = total_ticks;
|
||||
}
|
||||
|
||||
if(end)
|
||||
break;
|
||||
}
|
||||
|
||||
*ticks = total_ticks;
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
static VC_CONTAINER_STATUS_T qsynth_get_duration(VC_CONTAINER_T *p_ctx)
|
||||
{
|
||||
VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
|
||||
VC_CONTAINER_STATUS_T status;
|
||||
QSYNTH_SEGMENT_T **seg = &(module->seg);
|
||||
uint32_t i, tracks, division = 0, max_ticks = 0, us_perclock = 500000;
|
||||
uint32_t end_uspc = 0, end_ticks = 0;
|
||||
int64_t end_time = 0;
|
||||
uint8_t fps = 1, dpf = 1;
|
||||
|
||||
if((*seg = malloc(sizeof(QSYNTH_SEGMENT_T) + HEADER_LENGTH)) == NULL)
|
||||
return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
(*seg)->next = NULL;
|
||||
(*seg)->len = HEADER_LENGTH;
|
||||
(*seg)->data = (uint8_t *) ((*seg) + 1);
|
||||
|
||||
if(PEEK_BYTES(p_ctx, (*seg)->data, HEADER_LENGTH) != HEADER_LENGTH)
|
||||
return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
|
||||
if((status = qsynth_read_header((*seg)->data, &tracks, &division, &fps, &dpf)) != VC_CONTAINER_SUCCESS)
|
||||
return status;
|
||||
|
||||
// if we have a suspiciously large number of tracks, this is probably a bad file
|
||||
if(tracks > MAX_TRACKS)
|
||||
return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
|
||||
SKIP_BYTES(p_ctx, HEADER_LENGTH);
|
||||
|
||||
seg = &((*seg)->next);
|
||||
module->filesize = HEADER_LENGTH;
|
||||
|
||||
if(division == 0)
|
||||
{
|
||||
us_perclock = 1000000 / (fps * dpf);
|
||||
division = 1;
|
||||
}
|
||||
|
||||
for(i=0; i<tracks; i++)
|
||||
{
|
||||
uint32_t len, ticks, tempo_ticks;
|
||||
int64_t time;
|
||||
uint8_t dummy[8];
|
||||
|
||||
if(READ_BYTES(p_ctx, dummy, sizeof(dummy)) != sizeof(dummy) ||
|
||||
dummy[0] != 'M' || dummy[1] != 'T' || dummy[2] != 'r' || dummy[3] != 'k')
|
||||
return VC_CONTAINER_ERROR_FORMAT_INVALID;
|
||||
|
||||
len = BI32(dummy+4);
|
||||
|
||||
// impose a 1mb limit on track size
|
||||
if(len > (1<<20) || (*seg = malloc(sizeof(QSYNTH_SEGMENT_T) + 8 + len)) == NULL)
|
||||
return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
module->filesize += len+8;
|
||||
(*seg)->next = NULL;
|
||||
(*seg)->len = len + 8;
|
||||
(*seg)->data = (uint8_t *) ((*seg) + 1);
|
||||
|
||||
memcpy((*seg)->data, dummy, 8);
|
||||
if(READ_BYTES(p_ctx, (*seg)->data+8, len) != len)
|
||||
return VC_CONTAINER_ERROR_FORMAT_INVALID;
|
||||
|
||||
if((status = qsynth_read_track(*seg, &ticks, &time, &us_perclock, &tempo_ticks)) != VC_CONTAINER_SUCCESS)
|
||||
return status;
|
||||
|
||||
if(end_uspc == 0)
|
||||
{
|
||||
end_uspc = us_perclock;
|
||||
end_ticks = tempo_ticks;
|
||||
end_time = time;
|
||||
}
|
||||
|
||||
if(ticks > max_ticks)
|
||||
max_ticks = ticks;
|
||||
|
||||
seg = &((*seg)->next);
|
||||
}
|
||||
|
||||
if(end_uspc == 0)
|
||||
return VC_CONTAINER_ERROR_FORMAT_INVALID;
|
||||
|
||||
module->pass = module->seg;
|
||||
module->sent = 0;
|
||||
p_ctx->duration = (end_time + (((int64_t) (max_ticks - end_ticks)) * end_uspc)) / division;
|
||||
module->track->format->extradata = (uint8_t *) &module->filesize;
|
||||
module->track->format->extradata_size = 4;
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
Functions exported as part of the Container Module API
|
||||
*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T qsynth_reader_read( VC_CONTAINER_T *p_ctx,
|
||||
VC_CONTAINER_PACKET_T *packet,
|
||||
uint32_t flags )
|
||||
{
|
||||
VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
|
||||
|
||||
if(module->pass)
|
||||
{
|
||||
packet->size = module->pass->len - module->sent;
|
||||
packet->dts = packet->pts = 0;
|
||||
packet->track = 0;
|
||||
packet->flags = module->sent ? 0 : VC_CONTAINER_PACKET_FLAG_FRAME_START;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(module->timestamp > p_ctx->duration)
|
||||
return VC_CONTAINER_ERROR_EOS;
|
||||
|
||||
packet->size = 5;
|
||||
packet->dts = packet->pts = module->timestamp;
|
||||
packet->track = 0;
|
||||
packet->flags = VC_CONTAINER_PACKET_FLAG_FRAME;
|
||||
}
|
||||
|
||||
if(flags & VC_CONTAINER_READ_FLAG_SKIP)
|
||||
{
|
||||
if(module->pass)
|
||||
{
|
||||
module->pass = module->pass->next;
|
||||
module->sent = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// if we're playing then we can't really skip, but have to simulate a seek instead
|
||||
module->seek = 1;
|
||||
module->timestamp += 40;
|
||||
}
|
||||
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
if(flags & VC_CONTAINER_READ_FLAG_INFO)
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
|
||||
// read frame into packet->data
|
||||
if(module->pass)
|
||||
{
|
||||
uint32_t copy = MIN(packet->size, packet->buffer_size);
|
||||
memcpy(packet->data, module->pass->data + module->sent, copy);
|
||||
packet->size = copy;
|
||||
|
||||
if((module->sent += copy) == module->pass->len)
|
||||
{
|
||||
module->pass = module->pass->next;
|
||||
module->sent = 0;
|
||||
packet->flags |= VC_CONTAINER_PACKET_FLAG_FRAME_END;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(packet->buffer_size < packet->size)
|
||||
return VC_CONTAINER_ERROR_BUFFER_TOO_SMALL;
|
||||
|
||||
if(module->seek)
|
||||
{
|
||||
uint32_t current_time = module->timestamp / 1000;
|
||||
|
||||
packet->data[0] = 'S';
|
||||
packet->data[1] = (uint8_t)((current_time >> 24) & 0xFF);
|
||||
packet->data[2] = (uint8_t)((current_time >> 16) & 0xFF);
|
||||
packet->data[3] = (uint8_t)((current_time >> 8) & 0xFF);
|
||||
packet->data[4] = (uint8_t)((current_time ) & 0xFF);
|
||||
module->seek = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
packet->data[0] = 'P';
|
||||
packet->data[1] = 0;
|
||||
packet->data[2] = 0;
|
||||
packet->data[3] = 0;
|
||||
packet->data[4] = 40;
|
||||
module->timestamp += 40 * 1000;
|
||||
}
|
||||
}
|
||||
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T qsynth_reader_seek( VC_CONTAINER_T *p_ctx,
|
||||
int64_t *offset,
|
||||
VC_CONTAINER_SEEK_MODE_T mode,
|
||||
VC_CONTAINER_SEEK_FLAGS_T flags)
|
||||
{
|
||||
VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
|
||||
VC_CONTAINER_PARAM_UNUSED(flags);
|
||||
|
||||
if (mode != VC_CONTAINER_SEEK_MODE_TIME)
|
||||
return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
|
||||
|
||||
if(*offset < 0)
|
||||
*offset = 0;
|
||||
else if(*offset > p_ctx->duration)
|
||||
*offset = p_ctx->duration;
|
||||
|
||||
module->timestamp = *offset;
|
||||
module->seek = 1;
|
||||
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T qsynth_reader_close( VC_CONTAINER_T *p_ctx )
|
||||
{
|
||||
VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
|
||||
QSYNTH_SEGMENT_T *seg = module->seg;
|
||||
for(; p_ctx->tracks_num > 0; p_ctx->tracks_num--)
|
||||
vc_container_free_track(p_ctx, p_ctx->tracks[p_ctx->tracks_num-1]);
|
||||
while(seg != NULL)
|
||||
{
|
||||
QSYNTH_SEGMENT_T *next = seg->next;
|
||||
free(seg);
|
||||
seg = next;
|
||||
}
|
||||
free(module);
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_CONTAINER_STATUS_T qsynth_reader_open( VC_CONTAINER_T *p_ctx )
|
||||
{
|
||||
VC_CONTAINER_MODULE_T *module = 0;
|
||||
VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
uint8_t header[HEADER_LENGTH];
|
||||
|
||||
/* Check the file header */
|
||||
if((PEEK_BYTES(p_ctx, header, HEADER_LENGTH) != HEADER_LENGTH) ||
|
||||
qsynth_read_header(header, 0, 0, 0, 0) != VC_CONTAINER_SUCCESS)
|
||||
return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
|
||||
/* Allocate our context */
|
||||
module = malloc(sizeof(*module));
|
||||
if(!module) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
|
||||
memset(module, 0, sizeof(*module));
|
||||
p_ctx->priv->module = module;
|
||||
p_ctx->tracks_num = 1;
|
||||
p_ctx->tracks = &module->track;
|
||||
p_ctx->tracks[0] = vc_container_allocate_track(p_ctx, 0);
|
||||
if(!p_ctx->tracks[0]) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
|
||||
p_ctx->tracks[0]->format->es_type = VC_CONTAINER_ES_TYPE_AUDIO;
|
||||
p_ctx->tracks[0]->format->codec = VC_CONTAINER_CODEC_MIDI;
|
||||
p_ctx->tracks[0]->is_enabled = true;
|
||||
|
||||
if((status = qsynth_get_duration(p_ctx)) != VC_CONTAINER_SUCCESS) goto error;
|
||||
|
||||
LOG_DEBUG(p_ctx, "using qsynth reader");
|
||||
|
||||
p_ctx->capabilities = VC_CONTAINER_CAPS_CAN_SEEK;
|
||||
|
||||
p_ctx->priv->pf_close = qsynth_reader_close;
|
||||
p_ctx->priv->pf_read = qsynth_reader_read;
|
||||
p_ctx->priv->pf_seek = qsynth_reader_seek;
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
|
||||
error:
|
||||
LOG_DEBUG(p_ctx, "qsynth: error opening stream (%i)", status);
|
||||
if(module) qsynth_reader_close(p_ctx);
|
||||
return status;
|
||||
}
|
||||
|
||||
/********************************************************************************
|
||||
Entrypoint function
|
||||
********************************************************************************/
|
||||
|
||||
#if !defined(ENABLE_CONTAINERS_STANDALONE) && defined(__HIGHC__)
|
||||
# pragma weak reader_open qsynth_reader_open
|
||||
#endif
|
18
gfx/include/userland/containers/raw/CMakeLists.txt
Normal file
18
gfx/include/userland/containers/raw/CMakeLists.txt
Normal file
@ -0,0 +1,18 @@
|
||||
# Container module needs to go in as a plugins so different prefix
|
||||
# and install path
|
||||
set(CMAKE_SHARED_LIBRARY_PREFIX "")
|
||||
|
||||
# Make sure the compiler can find the necessary include files
|
||||
include_directories (../..)
|
||||
|
||||
add_library(reader_raw_video ${LIBRARY_TYPE} raw_video_reader.c)
|
||||
|
||||
target_link_libraries(reader_raw_video containers)
|
||||
|
||||
install(TARGETS reader_raw_video DESTINATION ${VMCS_PLUGIN_DIR})
|
||||
|
||||
add_library(writer_raw_video ${LIBRARY_TYPE} raw_video_writer.c)
|
||||
|
||||
target_link_libraries(writer_raw_video containers)
|
||||
|
||||
install(TARGETS writer_raw_video DESTINATION ${VMCS_PLUGIN_DIR})
|
66
gfx/include/userland/containers/raw/raw_video_common.h
Normal file
66
gfx/include/userland/containers/raw/raw_video_common.h
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef RAW_VIDEO_COMMON_H
|
||||
#define RAW_VIDEO_COMMON_H
|
||||
|
||||
static struct {
|
||||
const char *id;
|
||||
VC_CONTAINER_FOURCC_T codec;
|
||||
unsigned int size_num;
|
||||
unsigned int size_den;
|
||||
} table[] = {
|
||||
{"420", VC_CONTAINER_CODEC_I420, 3, 2},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
STATIC_INLINE bool from_yuv4mpeg2(const char *id, VC_CONTAINER_FOURCC_T *codec,
|
||||
unsigned int *size_num, unsigned int *size_den)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0; table[i].id; i++)
|
||||
if (!strcmp(id, table[i].id))
|
||||
break;
|
||||
if (codec) *codec = table[i].codec;
|
||||
if (size_num) *size_num = table[i].size_num;
|
||||
if (size_den) *size_den = table[i].size_den;
|
||||
return !!table[i].id;
|
||||
}
|
||||
|
||||
STATIC_INLINE bool to_yuv4mpeg2(VC_CONTAINER_FOURCC_T codec, const char **id,
|
||||
unsigned int *size_num, unsigned int *size_den)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0; table[i].id; i++)
|
||||
if (codec == table[i].codec)
|
||||
break;
|
||||
if (id) *id = table[i].id;
|
||||
if (size_num) *size_num = table[i].size_num;
|
||||
if (size_den) *size_den = table[i].size_den;
|
||||
return !!table[i].id;
|
||||
}
|
||||
|
||||
#endif /* RAW_VIDEO_COMMON_H */
|
465
gfx/include/userland/containers/raw/raw_video_reader.c
Normal file
465
gfx/include/userland/containers/raw/raw_video_reader.c
Normal file
@ -0,0 +1,465 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "containers/core/containers_private.h"
|
||||
#include "containers/core/containers_io_helpers.h"
|
||||
#include "containers/core/containers_utils.h"
|
||||
#include "containers/core/containers_logging.h"
|
||||
|
||||
#include "raw_video_common.h"
|
||||
|
||||
/******************************************************************************
|
||||
Defines.
|
||||
******************************************************************************/
|
||||
#define FILE_HEADER_SIZE_MAX 1024
|
||||
#define FRAME_HEADER_SIZE_MAX 256
|
||||
#define OPTION_SIZE_MAX 32
|
||||
|
||||
/******************************************************************************
|
||||
Type definitions
|
||||
******************************************************************************/
|
||||
typedef struct VC_CONTAINER_MODULE_T
|
||||
{
|
||||
VC_CONTAINER_TRACK_T *track;
|
||||
VC_CONTAINER_STATUS_T status;
|
||||
|
||||
bool yuv4mpeg2;
|
||||
bool non_standard;
|
||||
char option[OPTION_SIZE_MAX];
|
||||
|
||||
bool frame_header;
|
||||
unsigned int frame_header_size;
|
||||
|
||||
int64_t data_offset;
|
||||
unsigned int block_size;
|
||||
unsigned int block_offset;
|
||||
unsigned int frames;
|
||||
|
||||
} VC_CONTAINER_MODULE_T;
|
||||
|
||||
/******************************************************************************
|
||||
Function prototypes
|
||||
******************************************************************************/
|
||||
VC_CONTAINER_STATUS_T rawvideo_reader_open( VC_CONTAINER_T * );
|
||||
|
||||
/******************************************************************************
|
||||
Local Functions
|
||||
******************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T read_yuv4mpeg2_option( VC_CONTAINER_T *ctx,
|
||||
unsigned int *bytes_left )
|
||||
{
|
||||
VC_CONTAINER_MODULE_T *module = ctx->priv->module;
|
||||
unsigned int size, i;
|
||||
|
||||
/* Start by skipping spaces */
|
||||
while (*bytes_left && PEEK_U8(ctx) == ' ')
|
||||
(*bytes_left)--, _SKIP_U8(ctx);
|
||||
|
||||
size = PEEK_BYTES(ctx, module->option,
|
||||
MIN(sizeof(module->option), *bytes_left));
|
||||
|
||||
/* The config option ends at next space or newline */
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
if (module->option[i] == ' ' || module->option[i] == 0x0a)
|
||||
{
|
||||
module->option[i] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == 0)
|
||||
return VC_CONTAINER_ERROR_NOT_FOUND;
|
||||
|
||||
*bytes_left -= i;
|
||||
SKIP_BYTES(ctx, i);
|
||||
|
||||
/* If option is too long, we just discard it */
|
||||
if (i == size)
|
||||
{
|
||||
while (*bytes_left && PEEK_U8(ctx) != ' ' && PEEK_U8(ctx) != 0x0a)
|
||||
(*bytes_left)--, _SKIP_U8(ctx);
|
||||
return VC_CONTAINER_ERROR_NOT_FOUND;
|
||||
}
|
||||
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
static VC_CONTAINER_STATUS_T read_yuv4mpeg2_file_header( VC_CONTAINER_T *ctx )
|
||||
{
|
||||
VC_CONTAINER_MODULE_T *module = ctx->priv->module;
|
||||
unsigned int bytes_left = FILE_HEADER_SIZE_MAX - 10;
|
||||
unsigned int value1, value2;
|
||||
char codec[OPTION_SIZE_MAX] = "420";
|
||||
uint8_t h[10];
|
||||
|
||||
/* Check for the YUV4MPEG2 signature */
|
||||
if (READ_BYTES(ctx, h, sizeof(h)) != sizeof(h))
|
||||
return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
|
||||
if (memcmp(h, "YUV4MPEG2 ", sizeof(h)))
|
||||
return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
|
||||
/* Parse parameters */
|
||||
while (read_yuv4mpeg2_option(ctx, &bytes_left) == VC_CONTAINER_SUCCESS)
|
||||
{
|
||||
if (sscanf(module->option, "W%i", &value1) == 1)
|
||||
ctx->tracks[0]->format->type->video.width = value1;
|
||||
else if (sscanf(module->option, "H%i", &value1) == 1)
|
||||
ctx->tracks[0]->format->type->video.height = value1;
|
||||
else if (sscanf(module->option, "S%i", &value1) == 1)
|
||||
module->block_size = value1;
|
||||
else if (sscanf(module->option, "F%i:%i", &value1, &value2) == 2)
|
||||
{
|
||||
ctx->tracks[0]->format->type->video.frame_rate_num = value1;
|
||||
ctx->tracks[0]->format->type->video.frame_rate_den = value2;
|
||||
}
|
||||
else if (sscanf(module->option, "A%i:%i", &value1, &value2) == 2)
|
||||
{
|
||||
ctx->tracks[0]->format->type->video.par_num = value1;
|
||||
ctx->tracks[0]->format->type->video.par_den = value2;
|
||||
}
|
||||
else if (module->option[0] == 'C')
|
||||
{
|
||||
strcpy(codec, module->option+1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check the end marker */
|
||||
if (_READ_U8(ctx) != 0x0a)
|
||||
{
|
||||
LOG_ERROR(ctx, "missing end of header marker");
|
||||
return VC_CONTAINER_ERROR_CORRUPTED;
|
||||
}
|
||||
|
||||
/* Find out which codec we are dealing with */
|
||||
if (from_yuv4mpeg2(codec, &ctx->tracks[0]->format->codec, &value1, &value2))
|
||||
{
|
||||
module->block_size = ctx->tracks[0]->format->type->video.width *
|
||||
ctx->tracks[0]->format->type->video.height * value1 / value2;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(&ctx->tracks[0]->format->codec, codec, 4);
|
||||
module->non_standard = true;
|
||||
}
|
||||
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
static VC_CONTAINER_STATUS_T read_yuv4mpeg2_frame_header( VC_CONTAINER_T *ctx )
|
||||
{
|
||||
VC_CONTAINER_MODULE_T *module = ctx->priv->module;
|
||||
unsigned int bytes_left = FRAME_HEADER_SIZE_MAX - 5;
|
||||
unsigned int value1;
|
||||
char header[5];
|
||||
|
||||
if (READ_BYTES(ctx, header, sizeof(header)) != sizeof(header) ||
|
||||
memcmp(header, "FRAME", sizeof(header)))
|
||||
{
|
||||
LOG_ERROR(ctx, "missing frame marker");
|
||||
return STREAM_STATUS(ctx) != VC_CONTAINER_SUCCESS ?
|
||||
STREAM_STATUS(ctx) : VC_CONTAINER_ERROR_CORRUPTED;
|
||||
}
|
||||
|
||||
/* Parse parameters */
|
||||
while (read_yuv4mpeg2_option(ctx, &bytes_left) == VC_CONTAINER_SUCCESS)
|
||||
{
|
||||
if (module->non_standard && sscanf(module->option, "S%i", &value1) == 1)
|
||||
module->block_size = value1;
|
||||
}
|
||||
|
||||
/* Check the end marker */
|
||||
if (_READ_U8(ctx) != 0x0a)
|
||||
{
|
||||
LOG_ERROR(ctx, "missing end of frame header marker");
|
||||
return VC_CONTAINER_ERROR_CORRUPTED;
|
||||
}
|
||||
|
||||
module->frame_header_size = FRAME_HEADER_SIZE_MAX - bytes_left - 1;
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
static VC_CONTAINER_STATUS_T rawvideo_parse_uri( VC_CONTAINER_T *ctx,
|
||||
VC_CONTAINER_FOURCC_T *c, unsigned int *w, unsigned int *h,
|
||||
unsigned int *fr_num, unsigned int *fr_den, unsigned *block_size )
|
||||
{
|
||||
VC_CONTAINER_FOURCC_T codec = 0;
|
||||
unsigned int i, matches, width = 0, height = 0, fn = 0, fd = 0, size = 0;
|
||||
const char *uri = ctx->priv->io->uri;
|
||||
|
||||
/* Try and find a match for the string describing the format */
|
||||
for (i = 0; uri[i]; i++)
|
||||
{
|
||||
if (uri[i] != '_' && uri[i+1] != 'C')
|
||||
continue;
|
||||
|
||||
matches = sscanf(uri+i, "_C%4cW%iH%iF%i#%iS%i", (char *)&codec,
|
||||
&width, &height, &fn, &fd, &size);
|
||||
if (matches >= 3)
|
||||
break;
|
||||
}
|
||||
if (!uri[i])
|
||||
return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
|
||||
if (!size)
|
||||
{
|
||||
switch (codec)
|
||||
{
|
||||
case VC_CONTAINER_CODEC_I420:
|
||||
case VC_CONTAINER_CODEC_YV12:
|
||||
size = width * height * 3 / 2;
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!width || !height || !size)
|
||||
return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
|
||||
if (block_size) *block_size = size;
|
||||
if (c) *c = codec;
|
||||
if (w) *w = width;
|
||||
if (h) *h = height;
|
||||
if (fr_num) *fr_num = fn;
|
||||
if (fr_den) *fr_den = fd;
|
||||
if (block_size) *block_size = size;
|
||||
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
Functions exported as part of the Container Module API
|
||||
*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T rawvideo_reader_read( VC_CONTAINER_T *ctx,
|
||||
VC_CONTAINER_PACKET_T *packet, uint32_t flags )
|
||||
{
|
||||
VC_CONTAINER_MODULE_T *module = ctx->priv->module;
|
||||
unsigned int size;
|
||||
|
||||
if (module->status != VC_CONTAINER_SUCCESS)
|
||||
return module->status;
|
||||
|
||||
if (module->yuv4mpeg2 && !module->block_offset &&
|
||||
!module->frame_header)
|
||||
{
|
||||
module->status = read_yuv4mpeg2_frame_header(ctx);
|
||||
if (module->status != VC_CONTAINER_SUCCESS)
|
||||
return module->status;
|
||||
|
||||
module->frame_header = true;
|
||||
}
|
||||
|
||||
if (!module->block_offset)
|
||||
packet->pts = packet->dts = module->frames * INT64_C(1000000) *
|
||||
ctx->tracks[0]->format->type->video.frame_rate_den /
|
||||
ctx->tracks[0]->format->type->video.frame_rate_num;
|
||||
else
|
||||
packet->pts = packet->dts = VC_CONTAINER_TIME_UNKNOWN;
|
||||
packet->flags = VC_CONTAINER_PACKET_FLAG_FRAME_END |
|
||||
VC_CONTAINER_PACKET_FLAG_KEYFRAME;
|
||||
if (!module->block_offset)
|
||||
packet->flags |= VC_CONTAINER_PACKET_FLAG_FRAME_START;
|
||||
packet->frame_size = module->block_size;
|
||||
packet->size = module->block_size - module->block_offset;
|
||||
packet->track = 0;
|
||||
|
||||
if (flags & VC_CONTAINER_READ_FLAG_SKIP)
|
||||
{
|
||||
size = SKIP_BYTES(ctx, packet->size);
|
||||
module->block_offset = 0;
|
||||
module->frames++;
|
||||
module->frame_header = 0;
|
||||
module->status = STREAM_STATUS(ctx);
|
||||
return module->status;
|
||||
}
|
||||
|
||||
if (flags & VC_CONTAINER_READ_FLAG_INFO)
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
|
||||
size = MIN(module->block_size - module->block_offset, packet->buffer_size);
|
||||
size = READ_BYTES(ctx, packet->data, size);
|
||||
module->block_offset += size;
|
||||
packet->size = size;
|
||||
|
||||
if (module->block_offset == module->block_size)
|
||||
{
|
||||
module->block_offset = 0;
|
||||
module->frame_header = 0;
|
||||
module->frames++;
|
||||
}
|
||||
|
||||
module->status = size ? VC_CONTAINER_SUCCESS : STREAM_STATUS(ctx);
|
||||
return module->status;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T rawvideo_reader_seek( VC_CONTAINER_T *ctx, int64_t *offset,
|
||||
VC_CONTAINER_SEEK_MODE_T mode, VC_CONTAINER_SEEK_FLAGS_T flags)
|
||||
{
|
||||
VC_CONTAINER_MODULE_T *module = ctx->priv->module;
|
||||
VC_CONTAINER_PARAM_UNUSED(mode);
|
||||
|
||||
module->frames = *offset *
|
||||
ctx->tracks[0]->format->type->video.frame_rate_num /
|
||||
ctx->tracks[0]->format->type->video.frame_rate_den / INT64_C(1000000);
|
||||
module->block_offset = 0;
|
||||
|
||||
if ((flags & VC_CONTAINER_SEEK_FLAG_FORWARD) &&
|
||||
module->frames * INT64_C(1000000) *
|
||||
ctx->tracks[0]->format->type->video.frame_rate_den /
|
||||
ctx->tracks[0]->format->type->video.frame_rate_num < *offset)
|
||||
module->frames++;
|
||||
|
||||
module->frame_header = 0;
|
||||
|
||||
module->status =
|
||||
SEEK(ctx, module->data_offset + module->frames *
|
||||
(module->block_size + module->frame_header_size));
|
||||
|
||||
return module->status;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T rawvideo_reader_close( VC_CONTAINER_T *ctx )
|
||||
{
|
||||
VC_CONTAINER_MODULE_T *module = ctx->priv->module;
|
||||
for (; ctx->tracks_num > 0; ctx->tracks_num--)
|
||||
vc_container_free_track(ctx, ctx->tracks[ctx->tracks_num-1]);
|
||||
free(module);
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_CONTAINER_STATUS_T rawvideo_reader_open( VC_CONTAINER_T *ctx )
|
||||
{
|
||||
VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_FORMAT_INVALID;
|
||||
const char *extension = vc_uri_path_extension(ctx->priv->uri);
|
||||
VC_CONTAINER_MODULE_T *module = 0;
|
||||
bool yuv4mpeg2 = false;
|
||||
uint8_t h[10];
|
||||
|
||||
/* Check if the user has specified a container */
|
||||
vc_uri_find_query(ctx->priv->uri, 0, "container", &extension);
|
||||
|
||||
/* Check for the YUV4MPEG2 signature */
|
||||
if (PEEK_BYTES(ctx, h, sizeof(h)) != sizeof(h))
|
||||
return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
if (!memcmp(h, "YUV4MPEG2 ", sizeof(h)))
|
||||
yuv4mpeg2 = true;
|
||||
|
||||
/* Or check if the extension is supported */
|
||||
if (!yuv4mpeg2 &&
|
||||
!(extension && !strcasecmp(extension, "yuv")))
|
||||
return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
|
||||
LOG_DEBUG(ctx, "using raw video reader");
|
||||
|
||||
/* Allocate our context */
|
||||
module = malloc(sizeof(*module));
|
||||
if (!module) return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
|
||||
memset(module, 0, sizeof(*module));
|
||||
ctx->priv->module = module;
|
||||
ctx->tracks_num = 1;
|
||||
ctx->tracks = &module->track;
|
||||
ctx->tracks[0] = vc_container_allocate_track(ctx, 0);
|
||||
if (!ctx->tracks[0])
|
||||
{
|
||||
status = VC_CONTAINER_ERROR_OUT_OF_MEMORY;
|
||||
goto error;
|
||||
}
|
||||
ctx->tracks[0]->format->es_type = VC_CONTAINER_ES_TYPE_VIDEO;
|
||||
ctx->tracks[0]->is_enabled = true;
|
||||
ctx->tracks[0]->format->type->video.frame_rate_num = 25;
|
||||
ctx->tracks[0]->format->type->video.frame_rate_den = 1;
|
||||
ctx->tracks[0]->format->type->video.par_num = 1;
|
||||
ctx->tracks[0]->format->type->video.par_den = 1;
|
||||
|
||||
if (yuv4mpeg2)
|
||||
{
|
||||
status = read_yuv4mpeg2_file_header(ctx);
|
||||
if (status != VC_CONTAINER_SUCCESS)
|
||||
goto error;
|
||||
|
||||
module->data_offset = STREAM_POSITION(ctx);
|
||||
|
||||
status = read_yuv4mpeg2_frame_header(ctx);
|
||||
if (status != VC_CONTAINER_SUCCESS)
|
||||
goto error;
|
||||
module->frame_header = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
VC_CONTAINER_FOURCC_T codec;
|
||||
unsigned int width, height, fr_num, fr_den, block_size;
|
||||
|
||||
status = rawvideo_parse_uri(ctx, &codec, &width, &height,
|
||||
&fr_num, &fr_den, &block_size);
|
||||
if (status != VC_CONTAINER_SUCCESS)
|
||||
goto error;
|
||||
ctx->tracks[0]->format->codec = codec;
|
||||
ctx->tracks[0]->format->type->video.width = width;
|
||||
ctx->tracks[0]->format->type->video.height = height;
|
||||
if (fr_num && fr_den)
|
||||
{
|
||||
ctx->tracks[0]->format->type->video.frame_rate_num = fr_num;
|
||||
ctx->tracks[0]->format->type->video.frame_rate_den = fr_den;
|
||||
}
|
||||
module->block_size = block_size;
|
||||
}
|
||||
|
||||
/*
|
||||
* We now have all the information we really need to start playing the stream
|
||||
*/
|
||||
|
||||
LOG_INFO(ctx, "rawvideo %4.4s/%ix%i/fps:%i:%i/size:%i",
|
||||
(char *)&ctx->tracks[0]->format->codec,
|
||||
ctx->tracks[0]->format->type->video.width,
|
||||
ctx->tracks[0]->format->type->video.height,
|
||||
ctx->tracks[0]->format->type->video.frame_rate_num,
|
||||
ctx->tracks[0]->format->type->video.frame_rate_den, module->block_size);
|
||||
ctx->priv->pf_close = rawvideo_reader_close;
|
||||
ctx->priv->pf_read = rawvideo_reader_read;
|
||||
ctx->priv->pf_seek = rawvideo_reader_seek;
|
||||
module->yuv4mpeg2 = yuv4mpeg2;
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
|
||||
error:
|
||||
LOG_DEBUG(ctx, "rawvideo: error opening stream (%i)", status);
|
||||
rawvideo_reader_close(ctx);
|
||||
return status;
|
||||
}
|
||||
|
||||
/********************************************************************************
|
||||
Entrypoint function
|
||||
********************************************************************************/
|
||||
|
||||
#if !defined(ENABLE_CONTAINERS_STANDALONE) && defined(__HIGHC__)
|
||||
# pragma weak reader_open rawvideo_reader_open
|
||||
#endif
|
264
gfx/include/userland/containers/raw/raw_video_writer.c
Normal file
264
gfx/include/userland/containers/raw/raw_video_writer.c
Normal file
@ -0,0 +1,264 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "containers/core/containers_private.h"
|
||||
#include "containers/core/containers_io_helpers.h"
|
||||
#include "containers/core/containers_utils.h"
|
||||
#include "containers/core/containers_logging.h"
|
||||
|
||||
#include "raw_video_common.h"
|
||||
|
||||
/******************************************************************************
|
||||
Defines.
|
||||
******************************************************************************/
|
||||
|
||||
/******************************************************************************
|
||||
Type definitions
|
||||
******************************************************************************/
|
||||
typedef struct VC_CONTAINER_MODULE_T
|
||||
{
|
||||
VC_CONTAINER_TRACK_T *track;
|
||||
bool yuv4mpeg2;
|
||||
bool header_done;
|
||||
bool non_standard;
|
||||
|
||||
} VC_CONTAINER_MODULE_T;
|
||||
|
||||
/******************************************************************************
|
||||
Function prototypes
|
||||
******************************************************************************/
|
||||
VC_CONTAINER_STATUS_T rawvideo_writer_open( VC_CONTAINER_T * );
|
||||
|
||||
/******************************************************************************
|
||||
Local Functions
|
||||
******************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T rawvideo_write_header( VC_CONTAINER_T *ctx )
|
||||
{
|
||||
VC_CONTAINER_MODULE_T *module = ctx->priv->module;
|
||||
unsigned int size;
|
||||
char line[128];
|
||||
const char *id;
|
||||
|
||||
size = snprintf(line, sizeof(line), "YUV4MPEG2 W%i H%i",
|
||||
ctx->tracks[0]->format->type->video.width,
|
||||
ctx->tracks[0]->format->type->video.height);
|
||||
if (size >= sizeof(line))
|
||||
return VC_CONTAINER_ERROR_OUT_OF_RESOURCES;
|
||||
WRITE_BYTES(ctx, line, size);
|
||||
|
||||
if (ctx->tracks[0]->format->type->video.frame_rate_num &&
|
||||
ctx->tracks[0]->format->type->video.frame_rate_den)
|
||||
{
|
||||
size = snprintf(line, sizeof(line), " F%i:%i",
|
||||
ctx->tracks[0]->format->type->video.frame_rate_num,
|
||||
ctx->tracks[0]->format->type->video.frame_rate_den);
|
||||
if (size >= sizeof(line))
|
||||
return VC_CONTAINER_ERROR_OUT_OF_RESOURCES;
|
||||
WRITE_BYTES(ctx, line, size);
|
||||
}
|
||||
|
||||
if (ctx->tracks[0]->format->type->video.par_num &&
|
||||
ctx->tracks[0]->format->type->video.par_den)
|
||||
{
|
||||
size = snprintf(line, sizeof(line), " A%i:%i",
|
||||
ctx->tracks[0]->format->type->video.par_num,
|
||||
ctx->tracks[0]->format->type->video.par_den);
|
||||
if (size >= sizeof(line))
|
||||
return VC_CONTAINER_ERROR_OUT_OF_RESOURCES;
|
||||
WRITE_BYTES(ctx, line, size);
|
||||
}
|
||||
|
||||
if (to_yuv4mpeg2(ctx->tracks[0]->format->codec, &id, 0, 0))
|
||||
{
|
||||
size = snprintf(line, sizeof(line), " C%s", id);
|
||||
}
|
||||
else
|
||||
{
|
||||
module->non_standard = true;
|
||||
size = snprintf(line, sizeof(line), " C%4.4s",
|
||||
(char *)&ctx->tracks[0]->format->codec);
|
||||
}
|
||||
if (size >= sizeof(line))
|
||||
return VC_CONTAINER_ERROR_OUT_OF_RESOURCES;
|
||||
WRITE_BYTES(ctx, line, size);
|
||||
|
||||
_WRITE_U8(ctx, 0x0a);
|
||||
module->header_done = true;
|
||||
return STREAM_STATUS(ctx);
|
||||
}
|
||||
|
||||
static VC_CONTAINER_STATUS_T simple_write_add_track( VC_CONTAINER_T *ctx,
|
||||
VC_CONTAINER_ES_FORMAT_T *format )
|
||||
{
|
||||
VC_CONTAINER_STATUS_T status;
|
||||
|
||||
/* Sanity check that we support the type of track being created */
|
||||
if (ctx->tracks_num)
|
||||
return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
|
||||
if (format->es_type != VC_CONTAINER_ES_TYPE_VIDEO)
|
||||
return VC_CONTAINER_ERROR_TRACK_FORMAT_NOT_SUPPORTED;
|
||||
|
||||
/* Allocate and initialise track data */
|
||||
ctx->tracks[0] = vc_container_allocate_track(ctx, 0);
|
||||
if (!ctx->tracks[0])
|
||||
return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
status = vc_container_track_allocate_extradata(ctx,
|
||||
ctx->tracks[0], format->extradata_size);
|
||||
if(status != VC_CONTAINER_SUCCESS)
|
||||
return status;
|
||||
|
||||
vc_container_format_copy(ctx->tracks[0]->format, format,
|
||||
format->extradata_size);
|
||||
ctx->tracks_num++;
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
Functions exported as part of the Container Module API
|
||||
*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T rawvideo_writer_close( VC_CONTAINER_T *ctx )
|
||||
{
|
||||
VC_CONTAINER_MODULE_T *module = ctx->priv->module;
|
||||
for (; ctx->tracks_num > 0; ctx->tracks_num--)
|
||||
vc_container_free_track(ctx, ctx->tracks[ctx->tracks_num-1]);
|
||||
free(module);
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T rawvideo_writer_write( VC_CONTAINER_T *ctx,
|
||||
VC_CONTAINER_PACKET_T *packet )
|
||||
{
|
||||
VC_CONTAINER_MODULE_T *module = ctx->priv->module;
|
||||
VC_CONTAINER_STATUS_T status;
|
||||
|
||||
if (module->yuv4mpeg2 && !module->header_done)
|
||||
{
|
||||
status = rawvideo_write_header(ctx);
|
||||
if (status != VC_CONTAINER_SUCCESS)
|
||||
return status;
|
||||
}
|
||||
|
||||
if (module->yuv4mpeg2 &&
|
||||
(packet->flags & VC_CONTAINER_PACKET_FLAG_FRAME_START))
|
||||
{
|
||||
/* Write the metadata */
|
||||
WRITE_BYTES(ctx, "FRAME", sizeof("FRAME")-1);
|
||||
|
||||
/* For formats not supported by the YUV4MPEG2 spec, we prepend
|
||||
* each frame with its size */
|
||||
if (module->non_standard)
|
||||
{
|
||||
unsigned int size;
|
||||
char line[32];
|
||||
size = snprintf(line, sizeof(line), " S%i",
|
||||
packet->frame_size ? packet->frame_size : packet->size);
|
||||
if (size < sizeof(line))
|
||||
WRITE_BYTES(ctx, line, size);
|
||||
}
|
||||
|
||||
_WRITE_U8(ctx, 0x0a);
|
||||
}
|
||||
|
||||
/* Write the elementary stream */
|
||||
WRITE_BYTES(ctx, packet->data, packet->size);
|
||||
|
||||
return STREAM_STATUS(ctx);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T rawvideo_writer_control( VC_CONTAINER_T *ctx,
|
||||
VC_CONTAINER_CONTROL_T operation, va_list args )
|
||||
{
|
||||
VC_CONTAINER_MODULE_T *module = ctx->priv->module;
|
||||
VC_CONTAINER_ES_FORMAT_T *format;
|
||||
|
||||
switch (operation)
|
||||
{
|
||||
case VC_CONTAINER_CONTROL_TRACK_ADD:
|
||||
format = (VC_CONTAINER_ES_FORMAT_T *)va_arg(args, VC_CONTAINER_ES_FORMAT_T *);
|
||||
return simple_write_add_track(ctx, format);
|
||||
|
||||
case VC_CONTAINER_CONTROL_TRACK_ADD_DONE:
|
||||
return module->yuv4mpeg2 ?
|
||||
rawvideo_write_header( ctx ) : VC_CONTAINER_SUCCESS;
|
||||
|
||||
default: return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_CONTAINER_STATUS_T rawvideo_writer_open( VC_CONTAINER_T *ctx )
|
||||
{
|
||||
VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_FORMAT_INVALID;
|
||||
const char *extension = vc_uri_path_extension(ctx->priv->uri);
|
||||
VC_CONTAINER_MODULE_T *module;
|
||||
bool yuv4mpeg2 = false;
|
||||
|
||||
/* Check if the user has specified a container */
|
||||
vc_uri_find_query(ctx->priv->uri, 0, "container", &extension);
|
||||
|
||||
/* Check we're the right writer for this */
|
||||
if(!extension)
|
||||
return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
if(!strcasecmp(extension, "y4m") || !strcasecmp(extension, "yuv4mpeg2"))
|
||||
yuv4mpeg2 = true;
|
||||
if(!yuv4mpeg2 && strcasecmp(extension, "yuv"))
|
||||
return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
|
||||
LOG_DEBUG(ctx, "using rawvideo writer");
|
||||
|
||||
/* Allocate our context */
|
||||
module = malloc(sizeof(*module));
|
||||
if (!module) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
|
||||
memset(module, 0, sizeof(*module));
|
||||
ctx->priv->module = module;
|
||||
ctx->tracks = &module->track;
|
||||
module->yuv4mpeg2 = yuv4mpeg2;
|
||||
|
||||
ctx->priv->pf_close = rawvideo_writer_close;
|
||||
ctx->priv->pf_write = rawvideo_writer_write;
|
||||
ctx->priv->pf_control = rawvideo_writer_control;
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
|
||||
error:
|
||||
LOG_DEBUG(ctx, "rawvideo: error opening stream (%i)", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
/********************************************************************************
|
||||
Entrypoint function
|
||||
********************************************************************************/
|
||||
|
||||
#if !defined(ENABLE_CONTAINERS_STANDALONE) && defined(__HIGHC__)
|
||||
# pragma weak writer_open rawvideo_writer_open
|
||||
#endif
|
13
gfx/include/userland/containers/rcv/CMakeLists.txt
Normal file
13
gfx/include/userland/containers/rcv/CMakeLists.txt
Normal file
@ -0,0 +1,13 @@
|
||||
# Container module needs to go in as a plugins so different prefix
|
||||
# and install path
|
||||
set(CMAKE_SHARED_LIBRARY_PREFIX "")
|
||||
|
||||
# Make sure the compiler can find the necessary include files
|
||||
include_directories (../..)
|
||||
|
||||
add_library(reader_rcv ${LIBRARY_TYPE} rcv_reader.c)
|
||||
|
||||
target_link_libraries(reader_rcv containers)
|
||||
|
||||
install(TARGETS reader_rcv DESTINATION ${VMCS_PLUGIN_DIR})
|
||||
|
358
gfx/include/userland/containers/rcv/rcv_reader.c
Normal file
358
gfx/include/userland/containers/rcv/rcv_reader.c
Normal file
@ -0,0 +1,358 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "containers/core/containers_private.h"
|
||||
#include "containers/core/containers_io_helpers.h"
|
||||
#include "containers/core/containers_utils.h"
|
||||
#include "containers/core/containers_index.h"
|
||||
#include "containers/core/containers_logging.h"
|
||||
|
||||
/******************************************************************************
|
||||
Defines.
|
||||
******************************************************************************/
|
||||
|
||||
#define LI32(b) (((b)[3]<<24)|((b)[2]<<16)|((b)[1]<<8)|((b)[0]))
|
||||
#define LI24(b) (((b)[2]<<16)|((b)[1]<<8)|((b)[0]))
|
||||
|
||||
/******************************************************************************
|
||||
Type definitions
|
||||
******************************************************************************/
|
||||
typedef struct {
|
||||
unsigned int num_frames : 24;
|
||||
unsigned int constant_c5 : 8;
|
||||
int constant_4;
|
||||
uint32_t struct_c;
|
||||
uint32_t vert_size;
|
||||
uint32_t horiz_size;
|
||||
int constant_c;
|
||||
uint32_t struct_b[2];
|
||||
uint32_t framerate;
|
||||
} RCV_FILE_HEADER_T;
|
||||
|
||||
typedef struct {
|
||||
unsigned int framesize : 24;
|
||||
unsigned int res : 7;
|
||||
unsigned int keyframe : 1;
|
||||
uint32_t timestamp;
|
||||
} RCV_FRAME_HEADER_T;
|
||||
|
||||
typedef struct VC_CONTAINER_MODULE_T
|
||||
{
|
||||
VC_CONTAINER_TRACK_T *track;
|
||||
uint8_t extradata[4];
|
||||
uint8_t mid_frame;
|
||||
uint32_t frame_read;
|
||||
RCV_FRAME_HEADER_T frame;
|
||||
VC_CONTAINER_INDEX_T *index; /* index of key frames */
|
||||
|
||||
} VC_CONTAINER_MODULE_T;
|
||||
|
||||
/******************************************************************************
|
||||
Function prototypes
|
||||
******************************************************************************/
|
||||
VC_CONTAINER_STATUS_T rcv_reader_open( VC_CONTAINER_T * );
|
||||
|
||||
/******************************************************************************
|
||||
Local Functions
|
||||
******************************************************************************/
|
||||
|
||||
static VC_CONTAINER_STATUS_T rcv_read_header(VC_CONTAINER_T *p_ctx)
|
||||
{
|
||||
VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
|
||||
RCV_FILE_HEADER_T header;
|
||||
uint8_t dummy[36];
|
||||
|
||||
if(PEEK_BYTES(p_ctx, dummy, sizeof(dummy)) != sizeof(dummy)) return VC_CONTAINER_ERROR_EOS;
|
||||
|
||||
header.num_frames = LI24(dummy);
|
||||
header.constant_c5 = dummy[3];
|
||||
header.constant_4 = LI32(dummy+4);
|
||||
|
||||
// extradata is just struct_c from the header
|
||||
memcpy(module->extradata, dummy+8, 4);
|
||||
module->track->format->extradata = module->extradata;
|
||||
module->track->format->extradata_size = 4;
|
||||
|
||||
module->track->format->type->video.height = LI32(dummy+12);
|
||||
module->track->format->type->video.width = LI32(dummy+16);
|
||||
|
||||
header.constant_c = LI32(dummy+20);
|
||||
memcpy(header.struct_b, dummy+24, 8);
|
||||
header.framerate = LI32(dummy+32);
|
||||
|
||||
if(header.constant_c5 != 0xc5 || header.constant_4 != 0x4 || header.constant_c != 0xc)
|
||||
return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
|
||||
if(header.framerate != 0 && header.framerate != 0xffffffffUL)
|
||||
{
|
||||
module->track->format->type->video.frame_rate_num = header.framerate;
|
||||
module->track->format->type->video.frame_rate_den = 1;
|
||||
}
|
||||
|
||||
// fill in general information
|
||||
if(header.num_frames != (1<<24)-1 && header.framerate != 0 && header.framerate != 0xffffffffUL)
|
||||
p_ctx->duration = ((int64_t) header.num_frames * 1000000LL) / (int64_t) header.framerate;
|
||||
|
||||
// we're happy that this is an rcv file
|
||||
SKIP_BYTES(p_ctx, sizeof(dummy));
|
||||
|
||||
return STREAM_STATUS(p_ctx);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Utility function to seek to the keyframe nearest the given timestamp.
|
||||
*
|
||||
* @param p_ctx Pointer to the container context.
|
||||
* @param timestamp The requested time. On success, this is updated with the time of the selected keyframe.
|
||||
* @param later If true, the selected frame is the earliest keyframe with a time greater or equal to timestamp.
|
||||
* If false, the selected frame is the latest keyframe with a time earlier or equal to timestamp.
|
||||
* @return Status code.
|
||||
*/
|
||||
static VC_CONTAINER_STATUS_T rcv_seek_nearest_keyframe(VC_CONTAINER_T *p_ctx, int64_t *timestamp, int later)
|
||||
{
|
||||
VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
|
||||
VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
|
||||
int64_t prev_keyframe_offset = sizeof(RCV_FILE_HEADER_T); /* set to very first frame */
|
||||
int64_t prev_keyframe_timestamp = 0;
|
||||
int use_prev_keyframe = !later;
|
||||
|
||||
if(use_prev_keyframe || (module->frame.timestamp * 1000LL > *timestamp))
|
||||
{
|
||||
/* A seek has been requested to an earlier keyframe, so rewind to the beginning
|
||||
* of the stream since there's no information available on previous frames */
|
||||
SEEK(p_ctx, sizeof(RCV_FILE_HEADER_T));
|
||||
memset(&module->frame, 0, sizeof(RCV_FRAME_HEADER_T));
|
||||
module->mid_frame = 0;
|
||||
module->frame_read = 0;
|
||||
}
|
||||
|
||||
if(module->mid_frame)
|
||||
{
|
||||
/* Seek back to the start of the current frame */
|
||||
SEEK(p_ctx, STREAM_POSITION(p_ctx) - module->frame_read - sizeof(RCV_FILE_HEADER_T));
|
||||
module->mid_frame = 0;
|
||||
module->frame_read = 0;
|
||||
}
|
||||
|
||||
while(1)
|
||||
{
|
||||
if(PEEK_BYTES(p_ctx, &module->frame, sizeof(RCV_FRAME_HEADER_T)) != sizeof(RCV_FRAME_HEADER_T))
|
||||
{
|
||||
status = VC_CONTAINER_ERROR_EOS;
|
||||
break;
|
||||
}
|
||||
|
||||
if(module->frame.keyframe)
|
||||
{
|
||||
if(module->index)
|
||||
vc_container_index_add(module->index, module->frame.timestamp * 1000LL, STREAM_POSITION(p_ctx));
|
||||
|
||||
if((module->frame.timestamp * 1000LL) >= *timestamp)
|
||||
{
|
||||
if((module->frame.timestamp * 1000LL) == *timestamp)
|
||||
use_prev_keyframe = 0;
|
||||
|
||||
*timestamp = module->frame.timestamp * 1000LL;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
prev_keyframe_offset = STREAM_POSITION(p_ctx);
|
||||
prev_keyframe_timestamp = module->frame.timestamp * 1000LL;
|
||||
}
|
||||
|
||||
SKIP_BYTES(p_ctx, module->frame.framesize + sizeof(RCV_FRAME_HEADER_T));
|
||||
}
|
||||
|
||||
if(use_prev_keyframe)
|
||||
{
|
||||
*timestamp = prev_keyframe_timestamp;
|
||||
status = SEEK(p_ctx, prev_keyframe_offset);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
Functions exported as part of the Container Module API
|
||||
*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T rcv_reader_read( VC_CONTAINER_T *p_ctx,
|
||||
VC_CONTAINER_PACKET_T *packet, uint32_t flags )
|
||||
{
|
||||
VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
|
||||
unsigned int size;
|
||||
|
||||
if(!module->mid_frame)
|
||||
{
|
||||
/* Save the current position for updating the indexer */
|
||||
int64_t position = STREAM_POSITION(p_ctx);
|
||||
|
||||
if(READ_BYTES(p_ctx, &module->frame, sizeof(RCV_FRAME_HEADER_T)) != sizeof(RCV_FRAME_HEADER_T))
|
||||
return VC_CONTAINER_ERROR_EOS;
|
||||
module->mid_frame = 1;
|
||||
module->frame_read = 0;
|
||||
|
||||
if(module->index && module->frame.keyframe)
|
||||
vc_container_index_add(module->index, (int64_t)module->frame.timestamp * 1000LL, position);
|
||||
}
|
||||
|
||||
packet->size = module->frame.framesize;
|
||||
packet->dts = packet->pts = module->frame.timestamp * 1000LL;
|
||||
packet->track = 0;
|
||||
packet->flags = 0;
|
||||
if(module->frame_read == 0)
|
||||
packet->flags |= VC_CONTAINER_PACKET_FLAG_FRAME_START;
|
||||
if(module->frame.keyframe)
|
||||
packet->flags |= VC_CONTAINER_PACKET_FLAG_KEYFRAME;
|
||||
|
||||
if(flags & VC_CONTAINER_READ_FLAG_SKIP)
|
||||
{
|
||||
size = SKIP_BYTES(p_ctx, module->frame.framesize - module->frame_read);
|
||||
if((module->frame_read += size) == module->frame.framesize)
|
||||
{
|
||||
module->frame_read = 0;
|
||||
module->mid_frame = 0;
|
||||
}
|
||||
return STREAM_STATUS(p_ctx);
|
||||
}
|
||||
|
||||
if(flags & VC_CONTAINER_READ_FLAG_INFO)
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
|
||||
size = MIN(module->frame.framesize - module->frame_read, packet->buffer_size);
|
||||
size = READ_BYTES(p_ctx, packet->data, size);
|
||||
if((module->frame_read += size) == module->frame.framesize)
|
||||
{
|
||||
module->frame_read = 0;
|
||||
module->mid_frame = 0;
|
||||
packet->flags |= VC_CONTAINER_PACKET_FLAG_FRAME_END;
|
||||
}
|
||||
packet->size = size;
|
||||
|
||||
return size ? VC_CONTAINER_SUCCESS : STREAM_STATUS(p_ctx);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T rcv_reader_seek( VC_CONTAINER_T *p_ctx, int64_t *offset,
|
||||
VC_CONTAINER_SEEK_MODE_T mode, VC_CONTAINER_SEEK_FLAGS_T flags)
|
||||
{
|
||||
int past = 1;
|
||||
int64_t position;
|
||||
int64_t timestamp = *offset;
|
||||
VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_FAILED;
|
||||
VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
|
||||
VC_CONTAINER_PARAM_UNUSED(mode);
|
||||
|
||||
if(module->index)
|
||||
status = vc_container_index_get(module->index, flags & VC_CONTAINER_SEEK_FLAG_FORWARD, ×tamp, &position, &past);
|
||||
|
||||
if(status == VC_CONTAINER_SUCCESS && !past)
|
||||
{
|
||||
/* Indexed keyframe found */
|
||||
module->frame_read = 0;
|
||||
module->mid_frame = 0;
|
||||
*offset = timestamp;
|
||||
status = SEEK(p_ctx, position);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No indexed keyframe found, so seek through all frames */
|
||||
status = rcv_seek_nearest_keyframe(p_ctx, offset, flags & VC_CONTAINER_SEEK_FLAG_FORWARD);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static VC_CONTAINER_STATUS_T rcv_reader_close( VC_CONTAINER_T *p_ctx )
|
||||
{
|
||||
VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
|
||||
for(; p_ctx->tracks_num > 0; p_ctx->tracks_num--)
|
||||
vc_container_free_track(p_ctx, p_ctx->tracks[p_ctx->tracks_num-1]);
|
||||
|
||||
if(module->index)
|
||||
vc_container_index_free(module->index);
|
||||
|
||||
free(module);
|
||||
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
VC_CONTAINER_STATUS_T rcv_reader_open( VC_CONTAINER_T *p_ctx )
|
||||
{
|
||||
VC_CONTAINER_MODULE_T *module = 0;
|
||||
VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
uint8_t dummy[8];
|
||||
|
||||
/* Quick check for a valid file header */
|
||||
if((PEEK_BYTES(p_ctx, dummy, sizeof(dummy)) != sizeof(dummy)) ||
|
||||
dummy[3] != 0xc5 || LI32(dummy+4) != 0x4)
|
||||
return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
|
||||
/* Allocate our context */
|
||||
module = malloc(sizeof(*module));
|
||||
if(!module) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
|
||||
memset(module, 0, sizeof(*module));
|
||||
p_ctx->priv->module = module;
|
||||
p_ctx->tracks_num = 1;
|
||||
p_ctx->tracks = &module->track;
|
||||
p_ctx->tracks[0] = vc_container_allocate_track(p_ctx, 0);
|
||||
if(!p_ctx->tracks[0]) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
|
||||
p_ctx->tracks[0]->format->es_type = VC_CONTAINER_ES_TYPE_VIDEO;
|
||||
p_ctx->tracks[0]->format->codec = VC_CONTAINER_CODEC_WMV3;
|
||||
p_ctx->tracks[0]->is_enabled = true;
|
||||
|
||||
if((status = rcv_read_header(p_ctx)) != VC_CONTAINER_SUCCESS) goto error;
|
||||
|
||||
LOG_DEBUG(p_ctx, "using rcv reader");
|
||||
|
||||
if(vc_container_index_create(&module->index, 512) == VC_CONTAINER_SUCCESS)
|
||||
vc_container_index_add(module->index, 0LL, STREAM_POSITION(p_ctx));
|
||||
|
||||
if(STREAM_SEEKABLE(p_ctx))
|
||||
p_ctx->capabilities |= VC_CONTAINER_CAPS_CAN_SEEK;
|
||||
|
||||
p_ctx->priv->pf_close = rcv_reader_close;
|
||||
p_ctx->priv->pf_read = rcv_reader_read;
|
||||
p_ctx->priv->pf_seek = rcv_reader_seek;
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
|
||||
error:
|
||||
if(module) rcv_reader_close(p_ctx);
|
||||
return status;
|
||||
}
|
||||
|
||||
/********************************************************************************
|
||||
Entrypoint function
|
||||
********************************************************************************/
|
||||
|
||||
#if !defined(ENABLE_CONTAINERS_STANDALONE) && defined(__HIGHC__)
|
||||
# pragma weak reader_open rcv_reader_open
|
||||
#endif
|
17
gfx/include/userland/containers/rtp/CMakeLists.txt
Normal file
17
gfx/include/userland/containers/rtp/CMakeLists.txt
Normal file
@ -0,0 +1,17 @@
|
||||
# Container module needs to go in as a plugins so different prefix
|
||||
# and install path
|
||||
set(CMAKE_SHARED_LIBRARY_PREFIX "")
|
||||
|
||||
# Make sure the compiler can find the necessary include files
|
||||
include_directories (../..)
|
||||
|
||||
set(rtp_SRCS ${rtp_SRCS} rtp_reader.c)
|
||||
set(rtp_SRCS ${rtp_SRCS} rtp_h264.c)
|
||||
set(rtp_SRCS ${rtp_SRCS} rtp_mpeg4.c)
|
||||
set(rtp_SRCS ${rtp_SRCS} rtp_base64.c)
|
||||
add_library(reader_rtp ${LIBRARY_TYPE} ${rtp_SRCS})
|
||||
|
||||
target_link_libraries(reader_rtp containers)
|
||||
|
||||
install(TARGETS reader_rtp DESTINATION ${VMCS_PLUGIN_DIR})
|
||||
|
165
gfx/include/userland/containers/rtp/rtp_base64.c
Normal file
165
gfx/include/userland/containers/rtp/rtp_base64.c
Normal file
@ -0,0 +1,165 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "rtp_base64.h"
|
||||
|
||||
/******************************************************************************
|
||||
Defines and constants.
|
||||
******************************************************************************/
|
||||
|
||||
#define LOWEST_BASE64_CHAR '+'
|
||||
#define HIGHEST_BASE64_CHAR 'z'
|
||||
#define IN_BASE64_RANGE(C) ((C) >= LOWEST_BASE64_CHAR && (C) <= HIGHEST_BASE64_CHAR)
|
||||
|
||||
/** Used as a marker in the lookup table to indicate an invalid Base64 character */
|
||||
#define INVALID 0xFF
|
||||
|
||||
/* Reduced lookup table for translating a character to a 6-bit value. The
|
||||
* table starts at the lowest Base64 character, '+' */
|
||||
uint8_t base64_decode_lookup[] = {
|
||||
62, INVALID, 62, INVALID, 63, /* '+' to '/' */
|
||||
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, /* '0' to '9' */
|
||||
INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, /* ':' to '@' */
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, /* 'A' to 'T' */
|
||||
20, 21, 22, 23, 24, 25, /* 'U' to 'Z' */
|
||||
INVALID, INVALID, INVALID, INVALID, 63, INVALID, /* '[' to '`' */
|
||||
26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, /* 'a' to 'r' */
|
||||
44, 45, 46, 47, 48, 49, 50, 51 /* 's' to 'z' */
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
Type definitions
|
||||
******************************************************************************/
|
||||
|
||||
/******************************************************************************
|
||||
Function prototypes
|
||||
******************************************************************************/
|
||||
|
||||
/******************************************************************************
|
||||
Local Functions
|
||||
******************************************************************************/
|
||||
|
||||
/*****************************************************************************
|
||||
Functions exported as part of the Base64 API
|
||||
*****************************************************************************/
|
||||
|
||||
/*****************************************************************************/
|
||||
uint32_t rtp_base64_byte_length(const char *str, uint32_t str_len)
|
||||
{
|
||||
uint32_t character_count = 0;
|
||||
uint32_t ii;
|
||||
char cc;
|
||||
|
||||
/* Scan through string until either a pad ('=') character or the end is
|
||||
* reached. Ignore characters that are not part of the Base64 alphabet.
|
||||
* Number of bytes should then be 3/4 of the character count. */
|
||||
|
||||
for (ii = 0; ii < str_len; ii++)
|
||||
{
|
||||
cc = *str++;
|
||||
if (cc == '=')
|
||||
break; /* Found a pad character: stop */
|
||||
|
||||
if (!IN_BASE64_RANGE(cc))
|
||||
continue; /* Ignore invalid character */
|
||||
|
||||
if (base64_decode_lookup[cc - LOWEST_BASE64_CHAR] != INVALID)
|
||||
character_count++;
|
||||
}
|
||||
|
||||
return (character_count * 3) >> 2;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
uint8_t *rtp_base64_decode(const char *str, uint32_t str_len, uint8_t *buffer, uint32_t buffer_len)
|
||||
{
|
||||
uint32_t character_count = 0;
|
||||
uint32_t value = 0;
|
||||
uint32_t ii;
|
||||
char cc;
|
||||
uint8_t lookup;
|
||||
|
||||
/* Build up sets of four characters (ignoring invalid ones) to generate
|
||||
* triplets of bytes, until either the end of the string or the pad ('=')
|
||||
* characters are reached. */
|
||||
|
||||
for (ii = 0; ii < str_len; ii++)
|
||||
{
|
||||
cc = *str++;
|
||||
if (cc == '=')
|
||||
break; /* Found a pad character: stop */
|
||||
|
||||
if (!IN_BASE64_RANGE(cc))
|
||||
continue; /* Ignore invalid character */
|
||||
|
||||
lookup = base64_decode_lookup[cc - LOWEST_BASE64_CHAR];
|
||||
if (lookup == INVALID)
|
||||
continue; /* Ignore invalid character */
|
||||
|
||||
value = (value << 6) | lookup;
|
||||
character_count++;
|
||||
|
||||
if (character_count == 4)
|
||||
{
|
||||
if (buffer_len < 3)
|
||||
return NULL; /* Not enough room in the output buffer */
|
||||
|
||||
*buffer++ = (uint8_t)(value >> 16);
|
||||
*buffer++ = (uint8_t)(value >> 8);
|
||||
*buffer++ = (uint8_t)(value );
|
||||
buffer_len -= 3;
|
||||
|
||||
character_count = 0;
|
||||
value = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* If there were extra characters on the end, these need to be handled to get
|
||||
* the last one or two bytes. */
|
||||
|
||||
switch (character_count)
|
||||
{
|
||||
case 0: /* Nothing more to do, the final bytes were converted in the loop */
|
||||
break;
|
||||
case 2: /* One additional byte, padded with four zero bits */
|
||||
if (!buffer_len)
|
||||
return NULL;
|
||||
*buffer++ = (uint8_t)(value >> 4);
|
||||
break;
|
||||
case 3: /* Two additional bytes, padded with two zero bits */
|
||||
if (buffer_len < 2)
|
||||
return NULL;
|
||||
*buffer++ = (uint8_t)(value >> 10);
|
||||
*buffer++ = (uint8_t)(value >> 2);
|
||||
break;
|
||||
default: /* This is an invalid Base64 encoding */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Return number of bytes written to the buffer */
|
||||
return buffer;
|
||||
}
|
49
gfx/include/userland/containers/rtp/rtp_base64.h
Normal file
49
gfx/include/userland/containers/rtp/rtp_base64.h
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _RTP_BASE64_H_
|
||||
#define _RTP_BASE64_H_
|
||||
|
||||
#include "containers/containers.h"
|
||||
|
||||
/** Returns the number of bytes encoded by the given Base64 encoded string.
|
||||
*
|
||||
* \param str The Base64 encoded string.
|
||||
* \param str_len The number of characters in the string.
|
||||
* \return The number of bytes that can be decoded. */
|
||||
uint32_t rtp_base64_byte_length(const char *str, uint32_t str_len);
|
||||
|
||||
/** Decodes a Base64 encoded string into a byte buffer.
|
||||
*
|
||||
* \param str The Base64 encoded string.
|
||||
* \param str_len The number of characters in the string.
|
||||
* \param buffer The buffer to receive the decoded output.
|
||||
* \param buffer_len The maximum number of bytes to put in the buffer.
|
||||
* \return Pointer to byte after the last one converted, or NULL on error. */
|
||||
uint8_t *rtp_base64_decode(const char *str, uint32_t str_len, uint8_t *buffer, uint32_t buffer_len);
|
||||
|
||||
#endif /* _RTP_BASE64_H_ */
|
803
gfx/include/userland/containers/rtp/rtp_h264.c
Normal file
803
gfx/include/userland/containers/rtp/rtp_h264.c
Normal file
@ -0,0 +1,803 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "containers/containers.h"
|
||||
|
||||
#include "containers/core/containers_logging.h"
|
||||
#include "containers/core/containers_list.h"
|
||||
#include "containers/core/containers_bits.h"
|
||||
#include "rtp_priv.h"
|
||||
#include "rtp_base64.h"
|
||||
#include "rtp_h264.h"
|
||||
|
||||
/******************************************************************************
|
||||
Defines and constants.
|
||||
******************************************************************************/
|
||||
|
||||
/** H.264 payload flag bits */
|
||||
typedef enum
|
||||
{
|
||||
H264F_NEXT_PACKET_IS_START = 0,
|
||||
H264F_INSIDE_FRAGMENT,
|
||||
H264F_OUTPUT_NAL_HEADER,
|
||||
} h264_flag_bit_t;
|
||||
|
||||
/** Bit mask to extract F zero bit from NAL unit header */
|
||||
#define NAL_UNIT_FZERO_MASK 0x80
|
||||
/** Bit mask to extract NAL unit type from NAL unit header */
|
||||
#define NAL_UNIT_TYPE_MASK 0x1F
|
||||
|
||||
/** NAL unit type codes */
|
||||
enum
|
||||
{
|
||||
/* 0 unspecified */
|
||||
NAL_UNIT_NON_IDR = 1,
|
||||
NAL_UNIT_PARTITION_A = 2,
|
||||
NAL_UNIT_PARTITION_B = 3,
|
||||
NAL_UNIT_PARTITION_C = 4,
|
||||
NAL_UNIT_IDR = 5,
|
||||
NAL_UNIT_SEI = 6,
|
||||
NAL_UNIT_SEQUENCE_PARAMETER_SET = 7,
|
||||
NAL_UNIT_PICTURE_PARAMETER_SET = 8,
|
||||
NAL_UNIT_ACCESS_UNIT_DELIMITER = 9,
|
||||
NAL_UNIT_END_OF_SEQUENCE = 10,
|
||||
NAL_UNIT_END_OF_STREAM = 11,
|
||||
NAL_UNIT_FILLER = 12,
|
||||
NAL_UNIT_EXT_SEQUENCE_PARAMETER_SET = 13,
|
||||
NAL_UNIT_PREFIX = 14,
|
||||
NAL_UNIT_SUBSET_SEQUENCE_PARAMETER_SET = 15,
|
||||
/* 16 to 18 reserved */
|
||||
NAL_UNIT_AUXILIARY = 19,
|
||||
NAL_UNIT_EXTENSION = 20,
|
||||
/* 21 to 23 reserved */
|
||||
NAL_UNIT_STAP_A = 24,
|
||||
NAL_UNIT_STAP_B = 25,
|
||||
NAL_UNIT_MTAP16 = 26,
|
||||
NAL_UNIT_MTAP24 = 27,
|
||||
NAL_UNIT_FU_A = 28,
|
||||
NAL_UNIT_FU_B = 29,
|
||||
/* 30 to 31 unspecified */
|
||||
};
|
||||
|
||||
/** Fragment unit header indicator bits */
|
||||
typedef enum
|
||||
{
|
||||
FRAGMENT_UNIT_HEADER_RESERVED = 5,
|
||||
FRAGMENT_UNIT_HEADER_END = 6,
|
||||
FRAGMENT_UNIT_HEADER_START = 7,
|
||||
} fragment_unit_header_bit_t;
|
||||
|
||||
#define MACROBLOCK_WIDTH 16
|
||||
#define MACROBLOCK_HEIGHT 16
|
||||
|
||||
/** H.264 RTP timestamp clock rate */
|
||||
#define H264_TIMESTAMP_CLOCK 90000
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CHROMA_FORMAT_MONO = 0,
|
||||
CHROMA_FORMAT_YUV_420 = 1,
|
||||
CHROMA_FORMAT_YUV_422 = 2,
|
||||
CHROMA_FORMAT_YUV_444 = 3,
|
||||
CHROMA_FORMAT_YUV_444_PLANAR = 4,
|
||||
CHROMA_FORMAT_RGB = 5,
|
||||
} CHROMA_FORMAT_T;
|
||||
|
||||
uint32_t chroma_sub_width[] = {
|
||||
1, 2, 2, 1, 1, 1
|
||||
};
|
||||
|
||||
uint32_t chroma_sub_height[] = {
|
||||
1, 2, 1, 1, 1, 1
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
Type definitions
|
||||
******************************************************************************/
|
||||
|
||||
typedef struct h264_payload_tag
|
||||
{
|
||||
uint32_t nal_unit_size; /**< Number of NAL unit bytes left to write */
|
||||
uint8_t flags; /**< H.264 payload flags */
|
||||
uint8_t header_bytes_to_write; /**< Number of start code bytes left to write */
|
||||
uint8_t nal_header; /**< Header for next NAL unit */
|
||||
} H264_PAYLOAD_T;
|
||||
|
||||
/******************************************************************************
|
||||
Function prototypes
|
||||
******************************************************************************/
|
||||
VC_CONTAINER_STATUS_T h264_parameter_handler(VC_CONTAINER_T *p_ctx,
|
||||
VC_CONTAINER_TRACK_T *track, const VC_CONTAINERS_LIST_T *params);
|
||||
|
||||
/******************************************************************************
|
||||
Local Functions
|
||||
******************************************************************************/
|
||||
|
||||
/**************************************************************************//**
|
||||
* Remove emulation prevention bytes from a buffer.
|
||||
* These are 0x03 bytes inserted to prevent misinterprentation of a byte
|
||||
* sequence in a buffer as a start code.
|
||||
*
|
||||
* @param sprop The buffer from which bytes are to be removed.
|
||||
* @param sprop_size The number of bytes in the buffer.
|
||||
* @return The new number of bytes in the buffer.
|
||||
*/
|
||||
static uint32_t h264_remove_emulation_prevention_bytes(uint8_t *sprop,
|
||||
uint32_t sprop_size)
|
||||
{
|
||||
uint32_t offset = 0;
|
||||
uint8_t nal_unit_type = sprop[offset++];
|
||||
uint32_t new_sprop_size = sprop_size;
|
||||
uint8_t first_byte, second_byte;
|
||||
|
||||
nal_unit_type &= 0x1F; /* Just keep NAL unit type bits */
|
||||
|
||||
/* Certain NAL unit types need a byte triplet passed first */
|
||||
if (nal_unit_type == NAL_UNIT_PREFIX || nal_unit_type == NAL_UNIT_EXTENSION)
|
||||
offset += 3;
|
||||
|
||||
/* Make sure there is enough data for there to be a 0x00 0x00 0x03 sequence */
|
||||
if (offset + 2 >= new_sprop_size)
|
||||
return new_sprop_size;
|
||||
|
||||
/* Keep a rolling set of the last couple of bytes */
|
||||
first_byte = sprop[offset++];
|
||||
second_byte = sprop[offset++];
|
||||
|
||||
while (offset < new_sprop_size)
|
||||
{
|
||||
uint8_t next_byte = sprop[offset];
|
||||
|
||||
if (!first_byte && !second_byte && next_byte == 0x03)
|
||||
{
|
||||
/* Remove the emulation prevention byte (0x03) */
|
||||
new_sprop_size--;
|
||||
if (offset == new_sprop_size) /* No more data to check */
|
||||
break;
|
||||
memmove(&sprop[offset], &sprop[offset + 1], new_sprop_size - offset);
|
||||
next_byte = sprop[offset];
|
||||
} else
|
||||
offset++;
|
||||
|
||||
first_byte = second_byte;
|
||||
second_byte = next_byte;
|
||||
}
|
||||
|
||||
return new_sprop_size;
|
||||
}
|
||||
|
||||
/**************************************************************************//**
|
||||
* Skip a scaling list in a bit stream.
|
||||
*
|
||||
* @param p_ctx The container context.
|
||||
* @param sprop The bit stream containing the scaling list.
|
||||
* @param size_of_scaling_list The size of the scaling list.
|
||||
*/
|
||||
static void h264_skip_scaling_list(VC_CONTAINER_T *p_ctx,
|
||||
VC_CONTAINER_BITS_T *sprop,
|
||||
uint32_t size_of_scaling_list)
|
||||
{
|
||||
uint32_t last_scale = 8;
|
||||
uint32_t next_scale = 8;
|
||||
int32_t delta_scale;
|
||||
uint32_t jj;
|
||||
|
||||
/* Algorithm taken from H.264 section 7.3.2.1.1.1 */
|
||||
for (jj = 0; jj < size_of_scaling_list; jj++)
|
||||
{
|
||||
if (next_scale)
|
||||
{
|
||||
delta_scale = BITS_READ_S32_EXP(p_ctx, sprop, "delta_scale");
|
||||
next_scale = (last_scale + delta_scale + 256) & 0xFF;
|
||||
|
||||
if (next_scale)
|
||||
last_scale = next_scale;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************//**
|
||||
* Get the chroma format from the bit stream.
|
||||
*
|
||||
* @param p_ctx The container context.
|
||||
* @param sprop The bit stream containing the scaling list.
|
||||
* @return The chroma format index.
|
||||
*/
|
||||
static uint32_t h264_get_chroma_format(VC_CONTAINER_T *p_ctx,
|
||||
VC_CONTAINER_BITS_T *sprop)
|
||||
{
|
||||
uint32_t chroma_format_idc;
|
||||
|
||||
chroma_format_idc = BITS_READ_U32_EXP(p_ctx, sprop, "chroma_format_idc");
|
||||
if (chroma_format_idc == 3 && BITS_READ_U32(p_ctx, sprop, 1, "separate_colour_plane_flag"))
|
||||
chroma_format_idc = CHROMA_FORMAT_YUV_444_PLANAR;
|
||||
|
||||
BITS_SKIP_EXP(p_ctx, sprop, "bit_depth_luma_minus8");
|
||||
BITS_SKIP_EXP(p_ctx, sprop, "bit_depth_chroma_minus8");
|
||||
BITS_SKIP(p_ctx, sprop, 1, "qpprime_y_zero_transform_bypass_flag");
|
||||
|
||||
if (BITS_READ_U32(p_ctx, sprop, 1, "seq_scaling_matrix_present_flag"))
|
||||
{
|
||||
uint32_t scaling_lists = (chroma_format_idc == 3) ? 12 : 8;
|
||||
uint32_t ii;
|
||||
|
||||
for (ii = 0; ii < scaling_lists; ii++)
|
||||
{
|
||||
if (BITS_READ_U32(p_ctx, sprop, 1, "seq_scaling_list_present_flag"))
|
||||
h264_skip_scaling_list(p_ctx, sprop, (ii < 6) ? 16 : 64);
|
||||
}
|
||||
}
|
||||
|
||||
return chroma_format_idc;
|
||||
}
|
||||
|
||||
/**************************************************************************//**
|
||||
* Decode an H.264 sequence parameter set and update track information.
|
||||
*
|
||||
* @param p_ctx The RTP container context.
|
||||
* @param track The track to be updated.
|
||||
* @param sprop The bit stream containing the sequence parameter set.
|
||||
* @return The resulting status of the function.
|
||||
*/
|
||||
static VC_CONTAINER_STATUS_T h264_decode_sequence_parameter_set(VC_CONTAINER_T *p_ctx,
|
||||
VC_CONTAINER_TRACK_T *track,
|
||||
VC_CONTAINER_BITS_T *sprop)
|
||||
{
|
||||
VC_CONTAINER_VIDEO_FORMAT_T *video = &track->format->type->video;
|
||||
uint32_t pic_order_cnt_type, chroma_format_idc;
|
||||
uint32_t pic_width_in_mbs_minus1, pic_height_in_map_units_minus1, frame_mbs_only_flag;
|
||||
uint32_t frame_crop_left_offset, frame_crop_right_offset, frame_crop_top_offset, frame_crop_bottom_offset;
|
||||
uint8_t profile_idc;
|
||||
|
||||
/* This structure is defined by H.264 section 7.3.2.1.1 */
|
||||
profile_idc = BITS_READ_U8(p_ctx, sprop, 8, "profile_idc");
|
||||
BITS_SKIP(p_ctx, sprop, 16, "Rest of profile_level_id");
|
||||
|
||||
BITS_READ_U32_EXP(p_ctx, sprop, "seq_parameter_set_id");
|
||||
|
||||
chroma_format_idc = CHROMA_FORMAT_RGB;
|
||||
if (profile_idc == 100 || profile_idc == 110 || profile_idc == 122 ||
|
||||
profile_idc == 244 || profile_idc == 44 || profile_idc == 83 ||
|
||||
profile_idc == 86 || profile_idc == 118 || profile_idc == 128)
|
||||
{
|
||||
chroma_format_idc = h264_get_chroma_format(p_ctx, sprop);
|
||||
if (chroma_format_idc > CHROMA_FORMAT_YUV_444_PLANAR)
|
||||
goto error;
|
||||
}
|
||||
|
||||
BITS_SKIP_EXP(p_ctx, sprop, "log2_max_frame_num_minus4");
|
||||
pic_order_cnt_type = BITS_READ_U32_EXP(p_ctx, sprop, "pic_order_cnt_type");
|
||||
if (pic_order_cnt_type == 0)
|
||||
{
|
||||
BITS_SKIP_EXP(p_ctx, sprop, "log2_max_pic_order_cnt_lsb_minus4");
|
||||
}
|
||||
else if (pic_order_cnt_type == 1)
|
||||
{
|
||||
uint32_t num_ref_frames_in_pic_order_cnt_cycle;
|
||||
uint32_t ii;
|
||||
|
||||
BITS_SKIP(p_ctx, sprop, 1, "delta_pic_order_always_zero_flag");
|
||||
BITS_SKIP_EXP(p_ctx, sprop, "offset_for_non_ref_pic");
|
||||
BITS_SKIP_EXP(p_ctx, sprop, "offset_for_top_to_bottom_field");
|
||||
num_ref_frames_in_pic_order_cnt_cycle = BITS_READ_U32_EXP(p_ctx, sprop, "num_ref_frames_in_pic_order_cnt_cycle");
|
||||
|
||||
for (ii = 0; ii < num_ref_frames_in_pic_order_cnt_cycle; ii++)
|
||||
BITS_SKIP_EXP(p_ctx, sprop, "offset_for_ref_frame");
|
||||
}
|
||||
|
||||
BITS_SKIP_EXP(p_ctx, sprop, "max_num_ref_frames");
|
||||
BITS_SKIP(p_ctx, sprop, 1, "gaps_in_frame_num_value_allowed_flag");
|
||||
|
||||
pic_width_in_mbs_minus1 = BITS_READ_U32_EXP(p_ctx, sprop, "pic_width_in_mbs_minus1");
|
||||
pic_height_in_map_units_minus1 = BITS_READ_U32_EXP(p_ctx, sprop, "pic_height_in_map_units_minus1");
|
||||
frame_mbs_only_flag = BITS_READ_U32(p_ctx, sprop, 1, "frame_mbs_only_flag");
|
||||
|
||||
/* Can now set the overall width and height in pixels */
|
||||
video->width = (pic_width_in_mbs_minus1 + 1) * MACROBLOCK_WIDTH;
|
||||
video->height = (2 - frame_mbs_only_flag) * (pic_height_in_map_units_minus1 + 1) * MACROBLOCK_HEIGHT;
|
||||
|
||||
if (!frame_mbs_only_flag)
|
||||
BITS_SKIP(p_ctx, sprop, 1, "mb_adaptive_frame_field_flag");
|
||||
BITS_SKIP(p_ctx, sprop, 1, "direct_8x8_inference_flag");
|
||||
|
||||
if (BITS_READ_U32(p_ctx, sprop, 1, "frame_cropping_flag"))
|
||||
{
|
||||
/* Visible area is restricted */
|
||||
frame_crop_left_offset = BITS_READ_U32_EXP(p_ctx, sprop, "frame_crop_left_offset");
|
||||
frame_crop_right_offset = BITS_READ_U32_EXP(p_ctx, sprop, "frame_crop_right_offset");
|
||||
frame_crop_top_offset = BITS_READ_U32_EXP(p_ctx, sprop, "frame_crop_top_offset");
|
||||
frame_crop_bottom_offset = BITS_READ_U32_EXP(p_ctx, sprop, "frame_crop_bottom_offset");
|
||||
|
||||
/* Need to adjust offsets for 4:2:0 and 4:2:2 chroma formats and field/frame flag */
|
||||
frame_crop_left_offset *= chroma_sub_width[chroma_format_idc];
|
||||
frame_crop_right_offset *= chroma_sub_width[chroma_format_idc];
|
||||
frame_crop_top_offset *= chroma_sub_height[chroma_format_idc] * (2 - frame_mbs_only_flag);
|
||||
frame_crop_bottom_offset *= chroma_sub_height[chroma_format_idc] * (2 - frame_mbs_only_flag);
|
||||
|
||||
if ((frame_crop_left_offset + frame_crop_right_offset) >= video->width ||
|
||||
(frame_crop_top_offset + frame_crop_bottom_offset) >= video->height)
|
||||
{
|
||||
LOG_ERROR(p_ctx, "H.264: frame crop offsets (%u, %u, %u, %u) larger than frame (%u, %u)",
|
||||
frame_crop_left_offset, frame_crop_right_offset, frame_crop_top_offset,
|
||||
frame_crop_bottom_offset, video->width, video->height);
|
||||
goto error;
|
||||
}
|
||||
|
||||
video->x_offset = frame_crop_left_offset;
|
||||
video->y_offset = frame_crop_top_offset;
|
||||
video->visible_width = video->width - frame_crop_left_offset - frame_crop_right_offset;
|
||||
video->visible_height = video->height - frame_crop_top_offset - frame_crop_bottom_offset;
|
||||
} else {
|
||||
video->visible_width = video->width;
|
||||
video->visible_height = video->height;
|
||||
}
|
||||
|
||||
/* vui_parameters may follow, but these will not be decoded */
|
||||
|
||||
if (!BITS_VALID(p_ctx, sprop))
|
||||
goto error;
|
||||
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
|
||||
error:
|
||||
LOG_ERROR(p_ctx, "H.264: sequence_parameter_set failed to decode");
|
||||
return VC_CONTAINER_ERROR_FORMAT_INVALID;
|
||||
}
|
||||
|
||||
/**************************************************************************//**
|
||||
* Decode an H.264 sprop and update track information.
|
||||
*
|
||||
* @param p_ctx The RTP container context.
|
||||
* @param track The track to be updated.
|
||||
* @param sprop The bit stream containing the sprop.
|
||||
* @return The resulting status of the function.
|
||||
*/
|
||||
static VC_CONTAINER_STATUS_T h264_decode_sprop(VC_CONTAINER_T *p_ctx,
|
||||
VC_CONTAINER_TRACK_T *track,
|
||||
VC_CONTAINER_BITS_T *sprop)
|
||||
{
|
||||
switch (BITS_READ_U32(p_ctx, sprop, 8, "nal_unit_header") & NAL_UNIT_TYPE_MASK)
|
||||
{
|
||||
case NAL_UNIT_SEQUENCE_PARAMETER_SET:
|
||||
return h264_decode_sequence_parameter_set(p_ctx, track, sprop);
|
||||
case NAL_UNIT_PICTURE_PARAMETER_SET:
|
||||
/* Not handled, but valid */
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
default:
|
||||
return VC_CONTAINER_ERROR_FORMAT_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************//**
|
||||
* Decode the sprop parameter sets URI parameter and update track information.
|
||||
*
|
||||
* @param p_ctx The RTP container context.
|
||||
* @param track The track to be updated.
|
||||
* @param params The URI parameter list.
|
||||
* @return The resulting status of the function.
|
||||
*/
|
||||
static VC_CONTAINER_STATUS_T h264_get_sprop_parameter_sets(VC_CONTAINER_T *p_ctx,
|
||||
VC_CONTAINER_TRACK_T *track,
|
||||
const VC_CONTAINERS_LIST_T *params)
|
||||
{
|
||||
VC_CONTAINER_STATUS_T status;
|
||||
PARAMETER_T param;
|
||||
size_t str_len;
|
||||
uint32_t extradata_size = 0;
|
||||
uint8_t *sprop;
|
||||
const char *set;
|
||||
const char *comma;
|
||||
|
||||
/* Get the value of sprop-parameter-sets, base64 decode the (comma separated)
|
||||
* sets, store all of them in track->priv->extradata and also decode to
|
||||
* validate and fill in video format info. */
|
||||
|
||||
param.name = "sprop-parameter-sets";
|
||||
if (!vc_containers_list_find_entry(params, ¶m) || !param.value)
|
||||
{
|
||||
LOG_ERROR(p_ctx, "H.264: sprop-parameter-sets is required, but not found");
|
||||
return VC_CONTAINER_ERROR_FORMAT_INVALID;
|
||||
}
|
||||
|
||||
/* First pass, calculate total size of buffer needed */
|
||||
set = param.value;
|
||||
do {
|
||||
comma = strchr(set, ',');
|
||||
str_len = comma ? (size_t)(comma - set) : strlen(set);
|
||||
/* Allow space for the NAL unit and a start code */
|
||||
extradata_size += rtp_base64_byte_length(set, str_len) + 4;
|
||||
set = comma + 1;
|
||||
} while (comma);
|
||||
|
||||
if (!extradata_size)
|
||||
{
|
||||
LOG_ERROR(p_ctx, "H.264: sprop-parameter-sets doesn't contain useful data");
|
||||
return VC_CONTAINER_ERROR_FORMAT_INVALID;
|
||||
}
|
||||
|
||||
status = vc_container_track_allocate_extradata(p_ctx, track, extradata_size);
|
||||
if(status != VC_CONTAINER_SUCCESS) return status;
|
||||
|
||||
track->format->extradata_size = extradata_size;
|
||||
sprop = track->priv->extradata;
|
||||
|
||||
/* Now decode the data into the buffer, and validate / use it to fill in format */
|
||||
set = param.value;
|
||||
do {
|
||||
uint8_t *next_sprop;
|
||||
uint32_t sprop_size;
|
||||
VC_CONTAINER_BITS_T sprop_stream;
|
||||
|
||||
comma = strchr(set, ',');
|
||||
str_len = comma ? (size_t)(comma - set) : strlen(set);
|
||||
|
||||
/* Insert a start code (0x00000001 in network order) */
|
||||
*sprop++ = 0x00; *sprop++ = 0x00; *sprop++ = 0x00; *sprop++ = 0x01;
|
||||
extradata_size -= 4;
|
||||
|
||||
next_sprop = rtp_base64_decode(set, str_len, sprop, extradata_size);
|
||||
if (!next_sprop)
|
||||
{
|
||||
LOG_ERROR(p_ctx, "H.264: sprop-parameter-sets failed to decode");
|
||||
return VC_CONTAINER_ERROR_FORMAT_INVALID;
|
||||
}
|
||||
|
||||
sprop_size = next_sprop - sprop;
|
||||
if (sprop_size)
|
||||
{
|
||||
uint32_t new_sprop_size;
|
||||
|
||||
/* Need to remove emulation prevention bytes before decoding */
|
||||
new_sprop_size = h264_remove_emulation_prevention_bytes(sprop, sprop_size);
|
||||
|
||||
BITS_INIT(p_ctx, &sprop_stream, sprop, new_sprop_size);
|
||||
status = h264_decode_sprop(p_ctx, track, &sprop_stream);
|
||||
if(status != VC_CONTAINER_SUCCESS) return status;
|
||||
|
||||
/* If necessary, decode sprop again, to put back the emulation prevention bytes */
|
||||
if (new_sprop_size != sprop_size)
|
||||
rtp_base64_decode(set, str_len, sprop, sprop_size);
|
||||
|
||||
extradata_size -= sprop_size;
|
||||
sprop = next_sprop;
|
||||
}
|
||||
|
||||
set = comma + 1;
|
||||
} while (comma);
|
||||
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/**************************************************************************//**
|
||||
* Check URI parameter list for unsupported features.
|
||||
*
|
||||
* @param p_ctx The RTP container context.
|
||||
* @param params The URI parameter list.
|
||||
* @return The resulting status of the function.
|
||||
*/
|
||||
static VC_CONTAINER_STATUS_T h264_check_unsupported_features(VC_CONTAINER_T *p_ctx,
|
||||
const VC_CONTAINERS_LIST_T *params)
|
||||
{
|
||||
uint32_t u32_unused;
|
||||
|
||||
/* Limitation: interleaving not yet supported */
|
||||
if (rtp_get_parameter_u32(params, "sprop-interleaving-depth", &u32_unused) ||
|
||||
rtp_get_parameter_u32(params, "sprop-deint-buf-req", &u32_unused) ||
|
||||
rtp_get_parameter_u32(params, "sprop-init-buf-time", &u32_unused) ||
|
||||
rtp_get_parameter_u32(params, "sprop-max-don-diff", &u32_unused))
|
||||
{
|
||||
LOG_ERROR(p_ctx, "H.264: Interleaved packetization is not supported");
|
||||
return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/**************************************************************************//**
|
||||
* Get and check the packetization mode URI parameter.
|
||||
*
|
||||
* @param p_ctx The RTP container context.
|
||||
* @param params The URI parameter list.
|
||||
* @return The resulting status of the function.
|
||||
*/
|
||||
static VC_CONTAINER_STATUS_T h264_get_packetization_mode(VC_CONTAINER_T *p_ctx,
|
||||
const VC_CONTAINERS_LIST_T *params)
|
||||
{
|
||||
uint32_t packetization_mode;
|
||||
|
||||
if (rtp_get_parameter_u32(params, "packetization-mode", &packetization_mode))
|
||||
{
|
||||
/* Only modes 0 and 1 are supported, no interleaving */
|
||||
if (packetization_mode > 1)
|
||||
{
|
||||
LOG_ERROR(p_ctx, "H.264: Unsupported packetization mode: %u", packetization_mode);
|
||||
return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
}
|
||||
}
|
||||
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/**************************************************************************//**
|
||||
* Initialise payload bit stream for a new RTP packet.
|
||||
*
|
||||
* @param p_ctx The RTP container context.
|
||||
* @param t_module The track module with the new RTP packet.
|
||||
* @return The resulting status of the function.
|
||||
*/
|
||||
static VC_CONTAINER_STATUS_T h264_new_rtp_packet(VC_CONTAINER_T *p_ctx,
|
||||
VC_CONTAINER_TRACK_MODULE_T *t_module)
|
||||
{
|
||||
VC_CONTAINER_BITS_T *payload = &t_module->payload;
|
||||
H264_PAYLOAD_T *extra = (H264_PAYLOAD_T *)t_module->extra;
|
||||
uint8_t unit_header;
|
||||
uint8_t fragment_header;
|
||||
|
||||
/* Read the NAL unit type and process as necessary */
|
||||
unit_header = BITS_READ_U8(p_ctx, payload, 8, "nal_unit_header");
|
||||
|
||||
/* When the top bit is set, the NAL unit is invalid */
|
||||
if (unit_header & NAL_UNIT_FZERO_MASK)
|
||||
{
|
||||
LOG_DEBUG(p_ctx, "H.264: Invalid NAL unit (top bit of header set)");
|
||||
return VC_CONTAINER_ERROR_FORMAT_INVALID;
|
||||
}
|
||||
|
||||
/* In most cases, a new packet means a new NAL unit, which will need a start code and the header */
|
||||
extra->header_bytes_to_write = 5;
|
||||
extra->nal_header = unit_header;
|
||||
extra->nal_unit_size = BITS_BYTES_AVAILABLE(p_ctx, payload);
|
||||
|
||||
switch (unit_header & NAL_UNIT_TYPE_MASK)
|
||||
{
|
||||
case NAL_UNIT_STAP_A:
|
||||
/* Single Time Aggregation Packet A */
|
||||
CLEAR_BIT(extra->flags, H264F_INSIDE_FRAGMENT);
|
||||
/* Trigger reading NAL unit length and header */
|
||||
extra->nal_unit_size = 0;
|
||||
break;
|
||||
|
||||
case NAL_UNIT_FU_A:
|
||||
/* Fragementation Unit A */
|
||||
fragment_header = BITS_READ_U8(p_ctx, payload, 8, "fragment_header");
|
||||
extra->nal_unit_size--;
|
||||
|
||||
if (BIT_IS_CLEAR(fragment_header, FRAGMENT_UNIT_HEADER_START) ||
|
||||
BIT_IS_SET(extra->flags, H264F_INSIDE_FRAGMENT))
|
||||
{
|
||||
/* This is a continuation packet, prevent start code and header from being output */
|
||||
extra->header_bytes_to_write = 0;
|
||||
|
||||
/* If this is the end of a fragment, the next FU will be a new one */
|
||||
if (BIT_IS_SET(fragment_header, FRAGMENT_UNIT_HEADER_END))
|
||||
CLEAR_BIT(extra->flags, H264F_INSIDE_FRAGMENT);
|
||||
} else {
|
||||
/* Start of a new fragment. */
|
||||
SET_BIT(extra->flags, H264F_INSIDE_FRAGMENT);
|
||||
|
||||
/* Merge type from fragment header and the rest from NAL unit header to form real NAL unit header */
|
||||
fragment_header &= NAL_UNIT_TYPE_MASK;
|
||||
fragment_header |= (unit_header & ~NAL_UNIT_TYPE_MASK);
|
||||
extra->nal_header = fragment_header;
|
||||
}
|
||||
break;
|
||||
|
||||
case NAL_UNIT_STAP_B:
|
||||
case NAL_UNIT_MTAP16:
|
||||
case NAL_UNIT_MTAP24:
|
||||
case NAL_UNIT_FU_B:
|
||||
LOG_ERROR(p_ctx, "H.264: Unsupported RTP NAL unit type: %u", unit_header & NAL_UNIT_TYPE_MASK);
|
||||
return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
|
||||
default:
|
||||
/* Single NAL unit case */
|
||||
CLEAR_BIT(extra->flags, H264F_INSIDE_FRAGMENT);
|
||||
}
|
||||
|
||||
return VC_CONTAINER_SUCCESS;
|
||||
}
|
||||
|
||||
/**************************************************************************//**
|
||||
* H.264 payload handler.
|
||||
* Extracts/skips data from the payload according to the NAL unit headers.
|
||||
*
|
||||
* @param p_ctx The RTP container context.
|
||||
* @param track The track being read.
|
||||
* @param p_packet The container packet information, or NULL.
|
||||
* @param flags The container read flags.
|
||||
* @return The resulting status of the function.
|
||||
*/
|
||||
static VC_CONTAINER_STATUS_T h264_payload_handler(VC_CONTAINER_T *p_ctx,
|
||||
VC_CONTAINER_TRACK_T *track,
|
||||
VC_CONTAINER_PACKET_T *p_packet,
|
||||
uint32_t flags)
|
||||
{
|
||||
VC_CONTAINER_TRACK_MODULE_T *t_module = track->priv->module;
|
||||
VC_CONTAINER_BITS_T *payload = &t_module->payload;
|
||||
H264_PAYLOAD_T *extra = (H264_PAYLOAD_T *)t_module->extra;
|
||||
uint32_t packet_flags = 0;
|
||||
uint8_t header_bytes_to_write;
|
||||
uint32_t size, offset;
|
||||
uint8_t *data_ptr;
|
||||
VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
|
||||
bool last_nal_unit_in_packet = false;
|
||||
|
||||
if (BIT_IS_SET(t_module->flags, TRACK_NEW_PACKET))
|
||||
{
|
||||
status = h264_new_rtp_packet(p_ctx, t_module);
|
||||
if (status != VC_CONTAINER_SUCCESS)
|
||||
return status;
|
||||
}
|
||||
|
||||
if (BIT_IS_SET(extra->flags, H264F_NEXT_PACKET_IS_START))
|
||||
{
|
||||
packet_flags |= VC_CONTAINER_PACKET_FLAG_FRAME_START;
|
||||
|
||||
if (!(flags & VC_CONTAINER_READ_FLAG_INFO))
|
||||
CLEAR_BIT(extra->flags, H264F_NEXT_PACKET_IS_START);
|
||||
}
|
||||
|
||||
if (!extra->nal_unit_size && BITS_BYTES_AVAILABLE(p_ctx, payload))
|
||||
{
|
||||
uint32_t stap_unit_header;
|
||||
|
||||
/* STAP-A packet: read NAL unit size and header from payload */
|
||||
stap_unit_header = BITS_READ_U32(p_ctx, payload, 24, "STAP unit header");
|
||||
extra->nal_unit_size = stap_unit_header >> 8;
|
||||
if (extra->nal_unit_size > BITS_BYTES_AVAILABLE(p_ctx, payload))
|
||||
{
|
||||
LOG_ERROR(p_ctx, "H.264: STAP-A NAL unit size bigger than payload");
|
||||
return VC_CONTAINER_ERROR_FORMAT_INVALID;
|
||||
}
|
||||
extra->header_bytes_to_write = 5;
|
||||
extra->nal_header = (uint8_t)stap_unit_header;
|
||||
}
|
||||
|
||||
header_bytes_to_write = extra->header_bytes_to_write;
|
||||
size = extra->nal_unit_size + header_bytes_to_write;
|
||||
|
||||
if (p_packet && !(flags & VC_CONTAINER_READ_FLAG_SKIP))
|
||||
{
|
||||
if (flags & VC_CONTAINER_READ_FLAG_INFO)
|
||||
{
|
||||
/* In order to set the frame end flag correctly, need to work out if this
|
||||
* is the only NAL unit or last in an aggregated packet */
|
||||
last_nal_unit_in_packet = (extra->nal_unit_size == BITS_BYTES_AVAILABLE(p_ctx, payload));
|
||||
} else {
|
||||
offset = 0;
|
||||
data_ptr = p_packet->data;
|
||||
|
||||
if (size > p_packet->buffer_size)
|
||||
{
|
||||
/* Buffer not big enough */
|
||||
size = p_packet->buffer_size;
|
||||
}
|
||||
|
||||
/* Insert start code and header into the data stream */
|
||||
while (offset < size && header_bytes_to_write)
|
||||
{
|
||||
uint8_t header_byte;
|
||||
|
||||
switch (header_bytes_to_write)
|
||||
{
|
||||
case 2: header_byte = 0x01; break;
|
||||
case 1: header_byte = extra->nal_header; break;
|
||||
default: header_byte = 0x00;
|
||||
}
|
||||
data_ptr[offset++] = header_byte;
|
||||
header_bytes_to_write--;
|
||||
}
|
||||
extra->header_bytes_to_write = header_bytes_to_write;
|
||||
|
||||
if (offset < size)
|
||||
{
|
||||
BITS_COPY_BYTES(p_ctx, payload, size - offset, data_ptr + offset, "Packet data");
|
||||
extra->nal_unit_size -= (size - offset);
|
||||
}
|
||||
|
||||
/* If we've read the final bytes of the packet, this must be the last (or only)
|
||||
* NAL unit in it */
|
||||
last_nal_unit_in_packet = !BITS_BYTES_AVAILABLE(p_ctx, payload);
|
||||
}
|
||||
p_packet->size = size;
|
||||
} else {
|
||||
extra->header_bytes_to_write = 0;
|
||||
BITS_SKIP_BYTES(p_ctx, payload, extra->nal_unit_size, "Packet data");
|
||||
last_nal_unit_in_packet = !BITS_BYTES_AVAILABLE(p_ctx, payload);
|
||||
extra->nal_unit_size = 0;
|
||||
}
|
||||
|
||||
/* The marker bit on an RTP packet indicates the frame ends at the end of packet */
|
||||
if (last_nal_unit_in_packet && BIT_IS_SET(t_module->flags, TRACK_HAS_MARKER))
|
||||
{
|
||||
packet_flags |= VC_CONTAINER_PACKET_FLAG_FRAME_END;
|
||||
|
||||
/* If this was the last packet of a frame, the next one must be the start */
|
||||
if (!(flags & VC_CONTAINER_READ_FLAG_INFO))
|
||||
SET_BIT(extra->flags, H264F_NEXT_PACKET_IS_START);
|
||||
}
|
||||
|
||||
if (p_packet)
|
||||
p_packet->flags = packet_flags;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
Functions exported as part of the RTP parameter handler API
|
||||
*****************************************************************************/
|
||||
|
||||
/**************************************************************************//**
|
||||
* H.264 parameter handler.
|
||||
* Parses the URI parameters to set up the track for an H.264 stream.
|
||||
*
|
||||
* @param p_ctx The reader context.
|
||||
* @param track The track to be updated.
|
||||
* @param params The URI parameter list.
|
||||
* @return The resulting status of the function.
|
||||
*/
|
||||
VC_CONTAINER_STATUS_T h264_parameter_handler(VC_CONTAINER_T *p_ctx,
|
||||
VC_CONTAINER_TRACK_T *track,
|
||||
const VC_CONTAINERS_LIST_T *params)
|
||||
{
|
||||
H264_PAYLOAD_T *extra;
|
||||
VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
|
||||
|
||||
VC_CONTAINER_PARAM_UNUSED(p_ctx);
|
||||
VC_CONTAINER_PARAM_UNUSED(params);
|
||||
|
||||
/* See RFC3984, section 8.1, for parameter names and details. */
|
||||
extra = (H264_PAYLOAD_T *)malloc(sizeof(H264_PAYLOAD_T));
|
||||
if (!extra)
|
||||
return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
|
||||
track->priv->module->extra = extra;
|
||||
memset(extra, 0, sizeof(H264_PAYLOAD_T));
|
||||
|
||||
/* Mandatory parameters */
|
||||
status = h264_get_sprop_parameter_sets(p_ctx, track, params);
|
||||
if (status != VC_CONTAINER_SUCCESS) return status;
|
||||
|
||||
/* Unsupported parameters */
|
||||
status = h264_check_unsupported_features(p_ctx, params);
|
||||
if (status != VC_CONTAINER_SUCCESS) return status;
|
||||
|
||||
/* Optional parameters */
|
||||
status = h264_get_packetization_mode(p_ctx, params);
|
||||
if (status != VC_CONTAINER_SUCCESS) return status;
|
||||
|
||||
track->priv->module->payload_handler = h264_payload_handler;
|
||||
SET_BIT(extra->flags, H264F_NEXT_PACKET_IS_START);
|
||||
|
||||
track->format->flags |= VC_CONTAINER_ES_FORMAT_FLAG_FRAMED;
|
||||
track->priv->module->timestamp_clock = H264_TIMESTAMP_CLOCK;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
42
gfx/include/userland/containers/rtp/rtp_h264.h
Normal file
42
gfx/include/userland/containers/rtp/rtp_h264.h
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _RTP_H264_H_
|
||||
#define _RTP_H264_H_
|
||||
|
||||
#include "containers/containers.h"
|
||||
#include "containers/core/containers_list.h"
|
||||
|
||||
/** H.264 parameter handler
|
||||
*
|
||||
* \param p_ctx Container context.
|
||||
* \param track Track data.
|
||||
* \param params Parameter list.
|
||||
* \return Status of decoding the H.264 parameters. */
|
||||
VC_CONTAINER_STATUS_T h264_parameter_handler(VC_CONTAINER_T *p_ctx, VC_CONTAINER_TRACK_T *track, const VC_CONTAINERS_LIST_T *params);
|
||||
|
||||
#endif /* _RTP_H264_H_ */
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user