summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2014-04-10 10:01:07 +0000
committerBenny Prijono <bennylp@teluu.com>2014-04-10 10:01:07 +0000
commit0aa83d8efcf477675669569b037f291464c4f146 (patch)
tree063ff3ade6100cb7e2a0693b153045027422fc53
parente7e444203e67583806aee77c0fc7d94115094efe (diff)
Re #1758: Initial implementation of OpenH264 wrapper. Supports:
- library detection via autoconf - CBP - packetization modes: 0, 1 - key frame request and indication - obey remote's fmtp Also added video codec test in samples (similar to the one in pjmedia test though). And there are some fixes here and there too (e.g. in vid_codec_util.c). git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@4815 74dad513-b988-da41-8d7b-12977e46ad98
-rwxr-xr-xaconfigure301
-rw-r--r--aconfigure.ac67
-rw-r--r--build.mak.in11
-rw-r--r--pjmedia/build/Makefile2
-rw-r--r--pjmedia/include/pjmedia-codec.h1
-rw-r--r--pjmedia/include/pjmedia-codec/openh264.h69
-rw-r--r--pjmedia/include/pjmedia/event.h5
-rw-r--r--pjmedia/src/pjmedia-codec/openh264.cpp1080
-rw-r--r--pjmedia/src/pjmedia/vid_codec_util.c2
-rw-r--r--pjmedia/src/test/vid_codec_test.c28
-rw-r--r--pjsip-apps/build/Samples.mak1
-rw-r--r--pjsip-apps/src/samples/aviplay.c9
-rw-r--r--pjsip-apps/src/samples/simpleua.c8
-rw-r--r--pjsip-apps/src/samples/vid_codec_test.c521
-rw-r--r--pjsip-apps/src/samples/vid_streamutil.c10
-rw-r--r--pjsip/src/pjsua-lib/pjsua_vid.c13
16 files changed, 2016 insertions, 112 deletions
diff --git a/aconfigure b/aconfigure
index af89e524..025e7e6d 100755
--- a/aconfigure
+++ b/aconfigure
@@ -1,9 +1,11 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for pjproject 2.x.
+# Generated by GNU Autoconf 2.68 for pjproject 2.x.
#
#
-# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software
+# Foundation, Inc.
#
#
# This configure script is free software; the Free Software Foundation
@@ -132,31 +134,6 @@ export LANGUAGE
# CDPATH.
(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
-# Use a proper internal environment variable to ensure we don't fall
- # into an infinite loop, continuously re-executing ourselves.
- if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
- _as_can_reexec=no; export _as_can_reexec;
- # We cannot yet assume a decent shell, so we have to provide a
-# neutralization value for shells without unset; and this also
-# works around shells that cannot unset nonexistent variables.
-# Preserve -v and -x to the replacement shell.
-BASH_ENV=/dev/null
-ENV=/dev/null
-(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
-case $- in # ((((
- *v*x* | *x*v* ) as_opts=-vx ;;
- *v* ) as_opts=-v ;;
- *x* ) as_opts=-x ;;
- * ) as_opts= ;;
-esac
-exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
-# Admittedly, this is quite paranoid, since all the known shells bail
-# out after a failed `exec'.
-$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
-as_fn_exit 255
- fi
- # We don't want this to propagate to other subprocesses.
- { _as_can_reexec=; unset _as_can_reexec;}
if test "x$CONFIG_SHELL" = x; then
as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
emulate sh
@@ -190,8 +167,7 @@ if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
else
exitcode=1; echo positional parameters were not saved.
fi
-test x\$exitcode = x0 || exit 1
-test -x / || exit 1"
+test x\$exitcode = x0 || exit 1"
as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
@@ -236,25 +212,21 @@ IFS=$as_save_IFS
if test "x$CONFIG_SHELL" != x; then :
- export CONFIG_SHELL
- # We cannot yet assume a decent shell, so we have to provide a
-# neutralization value for shells without unset; and this also
-# works around shells that cannot unset nonexistent variables.
-# Preserve -v and -x to the replacement shell.
-BASH_ENV=/dev/null
-ENV=/dev/null
-(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
-case $- in # ((((
- *v*x* | *x*v* ) as_opts=-vx ;;
- *v* ) as_opts=-v ;;
- *x* ) as_opts=-x ;;
- * ) as_opts= ;;
-esac
-exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
-# Admittedly, this is quite paranoid, since all the known shells bail
-# out after a failed `exec'.
-$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
-exit 255
+ # We cannot yet assume a decent shell, so we have to provide a
+ # neutralization value for shells without unset; and this also
+ # works around shells that cannot unset nonexistent variables.
+ # Preserve -v and -x to the replacement shell.
+ BASH_ENV=/dev/null
+ ENV=/dev/null
+ (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+ export CONFIG_SHELL
+ case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+ esac
+ exec "$CONFIG_SHELL" $as_opts "$as_myself" ${1+"$@"}
fi
if test x$as_have_required = xno; then :
@@ -356,14 +328,6 @@ $as_echo X"$as_dir" |
} # as_fn_mkdir_p
-
-# as_fn_executable_p FILE
-# -----------------------
-# Test if FILE is an executable regular file.
-as_fn_executable_p ()
-{
- test -f "$1" && test -x "$1"
-} # as_fn_executable_p
# as_fn_append VAR VALUE
# ----------------------
# Append the text in VALUE to the end of the definition contained in VAR. Take
@@ -485,10 +449,6 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits
chmod +x "$as_me.lineno" ||
{ $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
- # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
- # already done that, so ensure we don't try to do so again and fall
- # in an infinite loop. This has already happened in practice.
- _as_can_reexec=no; export _as_can_reexec
# Don't try to exec as it changes $[0], causing all sort of problems
# (the dirname of $[0] is not the place where we might find the
# original and so on. Autoconf is especially sensitive to this).
@@ -523,16 +483,16 @@ if (echo >conf$$.file) 2>/dev/null; then
# ... but there are two gotchas:
# 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
# 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
- # In both cases, we have to default to `cp -pR'.
+ # In both cases, we have to default to `cp -p'.
ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
- as_ln_s='cp -pR'
+ as_ln_s='cp -p'
elif ln conf$$.file conf$$ 2>/dev/null; then
as_ln_s=ln
else
- as_ln_s='cp -pR'
+ as_ln_s='cp -p'
fi
else
- as_ln_s='cp -pR'
+ as_ln_s='cp -p'
fi
rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
rmdir conf$$.dir 2>/dev/null
@@ -544,8 +504,28 @@ else
as_mkdir_p=false
fi
-as_test_x='test -x'
-as_executable_p=as_fn_executable_p
+if test -x / >/dev/null 2>&1; then
+ as_test_x='test -x'
+else
+ if ls -dL / >/dev/null 2>&1; then
+ as_ls_L_option=L
+ else
+ as_ls_L_option=
+ fi
+ as_test_x='
+ eval sh -c '\''
+ if test -d "$1"; then
+ test -d "$1/.";
+ else
+ case $1 in #(
+ -*)set "./$1";;
+ esac;
+ case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
+ ???[sx]*):;;*)false;;esac;fi
+ '\'' sh
+ '
+fi
+as_executable_p=$as_test_x
# Sed expression to map a string onto a valid CPP name.
as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
@@ -638,6 +618,8 @@ libcrypto_present
libssl_present
openssl_h_present
ac_no_ssl
+ac_openh264_ldflags
+ac_openh264_cflags
ac_v4l2_ldflags
ac_v4l2_cflags
PKG_CONFIG
@@ -790,6 +772,8 @@ enable_sdl
with_ffmpeg
enable_ffmpeg
enable_v4l2
+with_openh264
+enable_openh264
enable_ipp
with_ipp
with_ipp_samples
@@ -1270,6 +1254,8 @@ target=$target_alias
if test "x$host_alias" != x; then
if test "x$build_alias" = x; then
cross_compiling=maybe
+ $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host.
+ If a cross compiler is detected then cross compile mode will be used" >&2
elif test "x$build_alias" != "x$host_alias"; then
cross_compiling=yes
fi
@@ -1453,6 +1439,7 @@ Optional Features:
--disable-sdl Disable SDL (default: not disabled)
--disable-ffmpeg Disable ffmpeg (default: not disabled)
--disable-v4l2 Disable Video4Linux2 (default: not disabled)
+ --disable-openh264 Disable OpenH264 (default: not disabled)
--enable-ipp Enable Intel IPP support. Specify the Intel IPP
package and samples location using IPPROOT and
IPPSAMPLES env var or with --with-ipp and
@@ -1491,6 +1478,7 @@ Optional Packages:
include/lib paths)
--with-sdl=DIR Specify alternate libSDL prefix
--with-ffmpeg=DIR Specify alternate FFMPEG prefix
+ --with-openh264=DIR Specify alternate OpenH264 prefix
--with-ipp=DIR Specify the Intel IPP location
--with-ipp-samples=DIR Specify the Intel IPP samples location
--with-ipp-arch=ARCH Specify the Intel IPP ARCH suffix, e.g. "64" or
@@ -1583,9 +1571,9 @@ test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
pjproject configure 2.x
-generated by GNU Autoconf 2.69
+generated by GNU Autoconf 2.68
-Copyright (C) 2012 Free Software Foundation, Inc.
+Copyright (C) 2010 Free Software Foundation, Inc.
This configure script is free software; the Free Software Foundation
gives unlimited permission to copy, distribute and modify it.
_ACEOF
@@ -1699,7 +1687,7 @@ $as_echo "$ac_try_echo"; } >&5
test ! -s conftest.err
} && test -s conftest$ac_exeext && {
test "$cross_compiling" = yes ||
- test -x conftest$ac_exeext
+ $as_test_x conftest$ac_exeext
}; then :
ac_retval=0
else
@@ -1986,7 +1974,7 @@ This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by pjproject $as_me 2.x, which was
-generated by GNU Autoconf 2.69. Invocation command line was
+generated by GNU Autoconf 2.68. Invocation command line was
$ $0 $@
@@ -2511,7 +2499,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_prog_CC="${ac_tool_prefix}gcc"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -2551,7 +2539,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_prog_ac_ct_CC="gcc"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -2604,7 +2592,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_prog_CC="${ac_tool_prefix}cc"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -2645,7 +2633,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
ac_prog_rejected=yes
continue
@@ -2703,7 +2691,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -2747,7 +2735,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_prog_ac_ct_CC="$ac_prog"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -3193,7 +3181,8 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdarg.h>
#include <stdio.h>
-struct stat;
+#include <sys/types.h>
+#include <sys/stat.h>
/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
struct buf { int x; };
FILE * (*rcsopen) (struct buf *, struct stat *, int);
@@ -3306,7 +3295,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_prog_CXX="$ac_tool_prefix$ac_prog"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -3350,7 +3339,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_prog_ac_ct_CXX="$ac_prog"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -3559,7 +3548,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -3599,7 +3588,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_prog_ac_ct_RANLIB="ranlib"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -3653,7 +3642,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_prog_AR="$ac_tool_prefix$ac_prog"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -3697,7 +3686,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_prog_ac_ct_AR="$ac_prog"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -4479,7 +4468,7 @@ do
for ac_prog in grep ggrep; do
for ac_exec_ext in '' $ac_executable_extensions; do
ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
- as_fn_executable_p "$ac_path_GREP" || continue
+ { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue
# Check for GNU ac_path_GREP and select it if it is found.
# Check for GNU $ac_path_GREP
case `"$ac_path_GREP" --version 2>&1` in
@@ -4545,7 +4534,7 @@ do
for ac_prog in egrep; do
for ac_exec_ext in '' $ac_executable_extensions; do
ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
- as_fn_executable_p "$ac_path_EGREP" || continue
+ { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue
# Check for GNU ac_path_EGREP and select it if it is found.
# Check for GNU $ac_path_EGREP
case `"$ac_path_EGREP" --version 2>&1` in
@@ -6512,7 +6501,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_path_SDL_CONFIG="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -6558,7 +6547,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_path_SDL_CONFIG="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -6663,7 +6652,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_prog_PKG_CONFIG="$ac_prog"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -7066,6 +7055,94 @@ fi
fi
+
+# Check whether --with-openh264 was given.
+if test "${with_openh264+set}" = set; then :
+ withval=$with_openh264;
+else
+ with_openh264=no
+
+fi
+
+
+if test "x$ac_cross_compile" != "x" -a "x$with_openh264" = "xno"; then
+ enable_openh264=no
+fi
+
+
+
+# Check whether --enable-openh264 was given.
+if test "${enable_openh264+set}" = set; then :
+ enableval=$enable_openh264;
+ if test "$enable_openh264" = "no"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: Checking if OpenH264 is disabled... yes" >&5
+$as_echo "Checking if OpenH264 is disabled... yes" >&6; }
+ fi
+
+else
+
+ if test "x$with_openh264" != "xno" -a "x$with_openh264" != "x"; then
+ OPENH264_PREFIX=$with_openh264
+ OPENH264_CFLAGS="-I$OPENH264_PREFIX/include"
+ OPENH264_LDFLAGS="-L$OPENH264_PREFIX/lib"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: Using OpenH264 prefix... $with_openh264" >&5
+$as_echo "Using OpenH264 prefix... $with_openh264" >&6; }
+ else
+ OPENH264_CFLAGS=""
+ OPENH264_LDFLAGS=""
+ fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking OpenH264 availability" >&5
+$as_echo_n "checking OpenH264 availability... " >&6; }
+
+ OPENH264_LIBS="-lwels"
+
+ SAVED_LIBS="$LIBS"
+ SAVED_LDFLAGS="$LDFLAGS"
+ SAVED_CFLAGS="$CFLAGS"
+
+ LIBS="$OPENH264_LIBS $LIBS"
+ LDFLAGS="$OPENH264_LDFLAGS $LDFLAGS"
+ CFLAGS="$OPENH264_CFLAGS $CFLAGS"
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <wels/codec_api.h>
+ #include <wels/codec_app_def.h>
+
+int
+main ()
+{
+int main() { CreateSVCEncoder(0); return 0; }
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_openh264_cflags="-DPJMEDIA_HAS_OPENH264_CODEC=1 $OPENH264_CFLAGS"
+ ac_openh264_ldflags="$OPENH264_LDFLAGS $OPENH264_LIBS"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5
+$as_echo "ok" >&6; }
+
+else
+
+ LIBS="$SAVED_LIBS"
+ LDFLAGS="$SAVED_LDFLAGS"
+ CFLAGS="$SAVED_CFLAGS"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5
+$as_echo "failed" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+
+
+fi
+
+
+
+
# Check whether --enable-ipp was given.
if test "${enable_ipp+set}" = set; then :
enableval=$enable_ipp;
@@ -8345,16 +8422,16 @@ if (echo >conf$$.file) 2>/dev/null; then
# ... but there are two gotchas:
# 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
# 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
- # In both cases, we have to default to `cp -pR'.
+ # In both cases, we have to default to `cp -p'.
ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
- as_ln_s='cp -pR'
+ as_ln_s='cp -p'
elif ln conf$$.file conf$$ 2>/dev/null; then
as_ln_s=ln
else
- as_ln_s='cp -pR'
+ as_ln_s='cp -p'
fi
else
- as_ln_s='cp -pR'
+ as_ln_s='cp -p'
fi
rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
rmdir conf$$.dir 2>/dev/null
@@ -8414,16 +8491,28 @@ else
as_mkdir_p=false
fi
-
-# as_fn_executable_p FILE
-# -----------------------
-# Test if FILE is an executable regular file.
-as_fn_executable_p ()
-{
- test -f "$1" && test -x "$1"
-} # as_fn_executable_p
-as_test_x='test -x'
-as_executable_p=as_fn_executable_p
+if test -x / >/dev/null 2>&1; then
+ as_test_x='test -x'
+else
+ if ls -dL / >/dev/null 2>&1; then
+ as_ls_L_option=L
+ else
+ as_ls_L_option=
+ fi
+ as_test_x='
+ eval sh -c '\''
+ if test -d "$1"; then
+ test -d "$1/.";
+ else
+ case $1 in #(
+ -*)set "./$1";;
+ esac;
+ case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
+ ???[sx]*):;;*)false;;esac;fi
+ '\'' sh
+ '
+fi
+as_executable_p=$as_test_x
# Sed expression to map a string onto a valid CPP name.
as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
@@ -8445,7 +8534,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# values after options handling.
ac_log="
This file was extended by pjproject $as_me 2.x, which was
-generated by GNU Autoconf 2.69. Invocation command line was
+generated by GNU Autoconf 2.68. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
CONFIG_HEADERS = $CONFIG_HEADERS
@@ -8507,10 +8596,10 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
pjproject config.status 2.x
-configured by $0, generated by GNU Autoconf 2.69,
+configured by $0, generated by GNU Autoconf 2.68,
with options \\"\$ac_cs_config\\"
-Copyright (C) 2012 Free Software Foundation, Inc.
+Copyright (C) 2010 Free Software Foundation, Inc.
This config.status script is free software; the Free Software Foundation
gives unlimited permission to copy, distribute and modify it."
@@ -8598,7 +8687,7 @@ fi
_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
if \$ac_cs_recheck; then
- set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
shift
\$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
CONFIG_SHELL='$SHELL'
diff --git a/aconfigure.ac b/aconfigure.ac
index e0da29ab..3af48d72 100644
--- a/aconfigure.ac
+++ b/aconfigure.ac
@@ -1095,6 +1095,73 @@ AC_ARG_ENABLE(v4l2,
)
])
+dnl # OpenH264 alt prefix
+AC_ARG_WITH(openh264,
+ AC_HELP_STRING([--with-openh264=DIR],
+ [Specify alternate OpenH264 prefix]),
+ [],
+ [with_openh264=no]
+ )
+
+dnl # Do not use default OpenH264 installation if we are cross-compiling
+if test "x$ac_cross_compile" != "x" -a "x$with_openh264" = "xno"; then
+ enable_openh264=no
+fi
+
+dnl # OpenH264
+AC_SUBST(ac_openh264_cflags)
+AC_SUBST(ac_openh264_ldflags)
+AC_ARG_ENABLE(openh264,
+ AC_HELP_STRING([--disable-openh264],
+ [Disable OpenH264 (default: not disabled)]),
+ [
+ if test "$enable_openh264" = "no"; then
+ AC_MSG_RESULT([Checking if OpenH264 is disabled... yes])
+ fi
+ ],
+ [
+ if test "x$with_openh264" != "xno" -a "x$with_openh264" != "x"; then
+ OPENH264_PREFIX=$with_openh264
+ OPENH264_CFLAGS="-I$OPENH264_PREFIX/include"
+ OPENH264_LDFLAGS="-L$OPENH264_PREFIX/lib"
+ AC_MSG_RESULT([Using OpenH264 prefix... $with_openh264])
+ else
+ OPENH264_CFLAGS=""
+ OPENH264_LDFLAGS=""
+ fi
+
+ AC_MSG_CHECKING([OpenH264 availability])
+
+ OPENH264_LIBS="-lwels"
+
+ SAVED_LIBS="$LIBS"
+ SAVED_LDFLAGS="$LDFLAGS"
+ SAVED_CFLAGS="$CFLAGS"
+
+ LIBS="$OPENH264_LIBS $LIBS"
+ LDFLAGS="$OPENH264_LDFLAGS $LDFLAGS"
+ CFLAGS="$OPENH264_CFLAGS $CFLAGS"
+
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <wels/codec_api.h>
+ #include <wels/codec_app_def.h>
+ ]],
+ [int main() { CreateSVCEncoder(0); return 0; }]
+ )],
+ [ ac_openh264_cflags="-DPJMEDIA_HAS_OPENH264_CODEC=1 $OPENH264_CFLAGS"
+ ac_openh264_ldflags="$OPENH264_LDFLAGS $OPENH264_LIBS"
+ AC_MSG_RESULT(ok)
+ ],
+ [
+ LIBS="$SAVED_LIBS"
+ LDFLAGS="$SAVED_LDFLAGS"
+ CFLAGS="$SAVED_CFLAGS"
+ AC_MSG_RESULT(failed)
+ ])
+
+ ])
+
+
+
dnl ########################################################
dnl # Intel IPP support
dnl #
diff --git a/build.mak.in b/build.mak.in
index 58e9a682..07f54baf 100644
--- a/build.mak.in
+++ b/build.mak.in
@@ -133,7 +133,7 @@ endif
SDL_CFLAGS = @ac_sdl_cflags@
SDL_LDFLAGS = @ac_sdl_ldflags@
-# FFMPEG dlags
+# FFMPEG flags
FFMPEG_CFLAGS = @ac_ffmpeg_cflags@
FFMPEG_LDFLAGS = @ac_ffmpeg_ldflags@
@@ -141,6 +141,10 @@ FFMPEG_LDFLAGS = @ac_ffmpeg_ldflags@
V4L2_CFLAGS = @ac_v4l2_cflags@
V4L2_LDFLAGS = @ac_v4l2_ldflags@
+# OPENH264 flags
+OPENH264_CFLAGS = @ac_openh264_cflags@
+OPENH264_LDFLAGS = @ac_openh264_ldflags@
+
# QT
AC_PJMEDIA_VIDEO_HAS_QT = @ac_pjmedia_video_has_qt@
QT_CFLAGS = @ac_qt_cflags@
@@ -150,8 +154,9 @@ IOS_CFLAGS = @ac_ios_cflags@
# PJMEDIA features exclusion
PJ_VIDEO_CFLAGS += $(SDL_CFLAGS) $(FFMPEG_CFLAGS) $(V4L2_CFLAGS) $(QT_CFLAGS) \
- $(IOS_CFLAGS)
-PJ_VIDEO_LDFLAGS += $(SDL_LDFLAGS) $(FFMPEG_LDFLAGS) $(V4L2_LDFLAGS)
+ $(OPENH264_CFLAGS) $(IOS_CFLAGS)
+PJ_VIDEO_LDFLAGS += $(SDL_LDFLAGS) $(FFMPEG_LDFLAGS) $(V4L2_LDFLAGS) \
+ $(OPENH264_LDFLAGS)
# CFLAGS, LDFLAGS, and LIBS to be used by applications
diff --git a/pjmedia/build/Makefile b/pjmedia/build/Makefile
index 23dc715e..9967ece6 100644
--- a/pjmedia/build/Makefile
+++ b/pjmedia/build/Makefile
@@ -134,7 +134,7 @@ export PJSDP_LDFLAGS += $(PJMEDIA_LDLIB) \
# Defines for building PJMEDIA-Codec library
#
export PJMEDIA_CODEC_SRCDIR = ../src/pjmedia-codec
-export PJMEDIA_CODEC_OBJS += audio_codecs.o ffmpeg_vid_codecs.o \
+export PJMEDIA_CODEC_OBJS += audio_codecs.o ffmpeg_vid_codecs.o openh264.o \
h263_packetizer.o h264_packetizer.o \
$(OS_OBJS) $(M_OBJS) $(CC_OBJS) $(HOST_OBJS) \
ipp_codecs.o opencore_amr.o silk.o $(CODEC_OBJS) \
diff --git a/pjmedia/include/pjmedia-codec.h b/pjmedia/include/pjmedia-codec.h
index 01e3e842..a35c8540 100644
--- a/pjmedia/include/pjmedia-codec.h
+++ b/pjmedia/include/pjmedia-codec.h
@@ -35,6 +35,7 @@
#include <pjmedia-codec/g7221.h>
#include <pjmedia-codec/ipp_codecs.h>
#include <pjmedia-codec/opencore_amr.h>
+#include <pjmedia-codec/openh264.h>
#include <pjmedia-codec/passthrough.h>
#include <pjmedia-codec/silk.h>
diff --git a/pjmedia/include/pjmedia-codec/openh264.h b/pjmedia/include/pjmedia-codec/openh264.h
new file mode 100644
index 00000000..d41ea428
--- /dev/null
+++ b/pjmedia/include/pjmedia-codec/openh264.h
@@ -0,0 +1,69 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2014 Teluu Inc. (http://www.teluu.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef __PJMEDIA_CODEC_OPENH264_H__
+#define __PJMEDIA_CODEC_OPENH264_H__
+
+#include <pjmedia-codec/types.h>
+#include <pjmedia/vid_codec.h>
+
+/**
+ * @file pjmedia-codec/openh264.h
+ * @brief Open H.264 codec
+ */
+
+
+PJ_BEGIN_DECL
+
+/**
+ * @defgroup PJMEDIA_CODEC_OPENH264 Open H.264 Codec
+ * @ingroup PJMEDIA_CODEC_VID_CODECS
+ * @{
+ */
+
+/**
+ * Initialize and register OpenH264 codec factory.
+ *
+ * @param mgr The video codec manager instance where this codec will
+ * be registered to. Specify NULL to use default instance
+ * (in that case, an instance of video codec manager must
+ * have been created beforehand).
+ * @param pf Pool factory.
+ *
+ * @return PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_codec_openh264_vid_init(pjmedia_vid_codec_mgr *mgr,
+ pj_pool_factory *pf);
+
+/**
+ * Unregister OpenH264 video codecs factory from the video codec manager and
+ * deinitialize the codec library.
+ *
+ * @return PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_codec_openh264_vid_deinit(void);
+
+
+/**
+ * @} PJMEDIA_CODEC_OPENH264
+ */
+
+
+PJ_END_DECL
+
+#endif /* __PJMEDIA_CODEC_OPENH264_H__ */
diff --git a/pjmedia/include/pjmedia/event.h b/pjmedia/include/pjmedia/event.h
index 84baba9d..360a648e 100644
--- a/pjmedia/include/pjmedia/event.h
+++ b/pjmedia/include/pjmedia/event.h
@@ -240,6 +240,11 @@ typedef pj_status_t pjmedia_event_cb(pjmedia_event *event,
typedef enum pjmedia_event_publish_flag
{
/**
+ * Default flag.
+ */
+ PJMEDIA_EVENT_PUBLISH_DEFAULT,
+
+ /**
* Publisher will only post the event to the event manager. It is the
* event manager that will later notify all the publisher's subscribers.
*/
diff --git a/pjmedia/src/pjmedia-codec/openh264.cpp b/pjmedia/src/pjmedia-codec/openh264.cpp
new file mode 100644
index 00000000..2f91ceb5
--- /dev/null
+++ b/pjmedia/src/pjmedia-codec/openh264.cpp
@@ -0,0 +1,1080 @@
+/* $Id$ */
+/*
+ * Copyright (C)2014 Teluu Inc. (http://www.teluu.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pjmedia-codec/openh264.h>
+#include <pjmedia-codec/h264_packetizer.h>
+#include <pjmedia/vid_codec_util.h>
+#include <pjmedia/errno.h>
+#include <pj/log.h>
+
+#if defined(PJMEDIA_HAS_OPENH264_CODEC) && \
+ PJMEDIA_HAS_OPENH264_CODEC != 0 && \
+ defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
+
+/* OpenH264: */
+#include <wels/codec_api.h>
+#include <wels/codec_app_def.h>
+
+/*
+ * Constants
+ */
+#define THIS_FILE "openh264.cpp"
+#define DEFAULT_WIDTH 720
+#define DEFAULT_HEIGHT 480
+#define DEFAULT_FPS 15
+#define DEFAULT_AVG_BITRATE 256000
+#define DEFAULT_MAX_BITRATE 256000
+
+#define MAX_RX_WIDTH 1200
+#define MAX_RX_HEIGHT 800
+
+
+/*
+ * Factory operations.
+ */
+static pj_status_t oh264_test_alloc(pjmedia_vid_codec_factory *factory,
+ const pjmedia_vid_codec_info *info );
+static pj_status_t oh264_default_attr(pjmedia_vid_codec_factory *factory,
+ const pjmedia_vid_codec_info *info,
+ pjmedia_vid_codec_param *attr );
+static pj_status_t oh264_enum_info(pjmedia_vid_codec_factory *factory,
+ unsigned *count,
+ pjmedia_vid_codec_info codecs[]);
+static pj_status_t oh264_alloc_codec(pjmedia_vid_codec_factory *factory,
+ const pjmedia_vid_codec_info *info,
+ pjmedia_vid_codec **p_codec);
+static pj_status_t oh264_dealloc_codec(pjmedia_vid_codec_factory *factory,
+ pjmedia_vid_codec *codec );
+
+
+/*
+ * Codec operations
+ */
+static pj_status_t oh264_codec_init(pjmedia_vid_codec *codec,
+ pj_pool_t *pool );
+static pj_status_t oh264_codec_open(pjmedia_vid_codec *codec,
+ pjmedia_vid_codec_param *param );
+static pj_status_t oh264_codec_close(pjmedia_vid_codec *codec);
+static pj_status_t oh264_codec_modify(pjmedia_vid_codec *codec,
+ const pjmedia_vid_codec_param *param);
+static pj_status_t oh264_codec_get_param(pjmedia_vid_codec *codec,
+ pjmedia_vid_codec_param *param);
+static pj_status_t oh264_codec_encode_begin(pjmedia_vid_codec *codec,
+ const pjmedia_vid_encode_opt *opt,
+ const pjmedia_frame *input,
+ unsigned out_size,
+ pjmedia_frame *output,
+ pj_bool_t *has_more);
+static pj_status_t oh264_codec_encode_more(pjmedia_vid_codec *codec,
+ unsigned out_size,
+ pjmedia_frame *output,
+ pj_bool_t *has_more);
+static pj_status_t oh264_codec_decode(pjmedia_vid_codec *codec,
+ pj_size_t count,
+ pjmedia_frame packets[],
+ unsigned out_size,
+ pjmedia_frame *output);
+
+/* Definition for OpenH264 codecs operations. */
+static pjmedia_vid_codec_op oh264_codec_op =
+{
+ &oh264_codec_init,
+ &oh264_codec_open,
+ &oh264_codec_close,
+ &oh264_codec_modify,
+ &oh264_codec_get_param,
+ &oh264_codec_encode_begin,
+ &oh264_codec_encode_more,
+ &oh264_codec_decode,
+ NULL
+};
+
+/* Definition for OpenH264 codecs factory operations. */
+static pjmedia_vid_codec_factory_op oh264_factory_op =
+{
+ &oh264_test_alloc,
+ &oh264_default_attr,
+ &oh264_enum_info,
+ &oh264_alloc_codec,
+ &oh264_dealloc_codec
+};
+
+
+static struct oh264_factory
+{
+ pjmedia_vid_codec_factory base;
+ pjmedia_vid_codec_mgr *mgr;
+ pj_pool_factory *pf;
+ pj_pool_t *pool;
+} oh264_factory;
+
+
+typedef struct oh264_codec_data
+{
+ pj_pool_t *pool;
+ pjmedia_vid_codec_param *prm;
+ pj_bool_t whole;
+ pjmedia_h264_packetizer *pktz;
+
+ /* Encoder state */
+ ISVCEncoder *enc;
+ SSourcePicture *esrc_pic;
+ unsigned enc_input_size;
+ pj_uint8_t *enc_frame_whole;
+ unsigned enc_frame_size;
+ unsigned enc_processed;
+ pj_timestamp ets;
+ SFrameBSInfo bsi;
+ int ilayer;
+
+ /* Decoder state */
+ ISVCDecoder *dec;
+ pj_uint8_t *dec_buf;
+ unsigned dec_buf_size;
+} oh264_codec_data;
+
+struct SLayerPEncCtx
+{
+ pj_int32_t iDLayerQp;
+ SSliceConfig sSliceCfg;
+};
+
+PJ_DEF(pj_status_t) pjmedia_codec_openh264_vid_init(pjmedia_vid_codec_mgr *mgr,
+ pj_pool_factory *pf)
+{
+ const pj_str_t h264_name = { (char*)"H264", 4};
+ pj_status_t status;
+
+ if (oh264_factory.pool != NULL) {
+ /* Already initialized. */
+ return PJ_SUCCESS;
+ }
+
+ if (!mgr) mgr = pjmedia_vid_codec_mgr_instance();
+ PJ_ASSERT_RETURN(mgr, PJ_EINVAL);
+
+ /* Create OpenH264 codec factory. */
+ oh264_factory.base.op = &oh264_factory_op;
+ oh264_factory.base.factory_data = NULL;
+ oh264_factory.mgr = mgr;
+ oh264_factory.pf = pf;
+ oh264_factory.pool = pj_pool_create(pf, "oh264factory", 256, 256, NULL);
+ if (!oh264_factory.pool)
+ return PJ_ENOMEM;
+
+ /* Registering format match for SDP negotiation */
+ status = pjmedia_sdp_neg_register_fmt_match_cb(
+ &h264_name,
+ &pjmedia_vid_codec_h264_match_sdp);
+ pj_assert(status == PJ_SUCCESS);
+
+ /* Register codec factory to codec manager. */
+ status = pjmedia_vid_codec_mgr_register_factory(mgr,
+ &oh264_factory.base);
+
+ PJ_LOG(4,(THIS_FILE, "OpenH264 codec initialized"));
+
+ /* Done. */
+ return PJ_SUCCESS;
+
+on_error:
+ pj_pool_release(oh264_factory.pool);
+ oh264_factory.pool = NULL;
+ return status;
+}
+
+/*
+ * Unregister OpenH264 codecs factory from pjmedia endpoint.
+ */
+PJ_DEF(pj_status_t) pjmedia_codec_openh264_vid_deinit(void)
+{
+ pj_status_t status = PJ_SUCCESS;
+
+ if (oh264_factory.pool == NULL) {
+ /* Already deinitialized */
+ return PJ_SUCCESS;
+ }
+
+ /* Unregister OpenH264 codecs factory. */
+ status = pjmedia_vid_codec_mgr_unregister_factory(oh264_factory.mgr,
+ &oh264_factory.base);
+
+ /* Destroy pool. */
+ pj_pool_release(oh264_factory.pool);
+ oh264_factory.pool = NULL;
+
+ return status;
+}
+
+static pj_status_t oh264_test_alloc(pjmedia_vid_codec_factory *factory,
+ const pjmedia_vid_codec_info *info )
+{
+ PJ_ASSERT_RETURN(factory == &oh264_factory.base, PJ_EINVAL);
+
+ if (info->fmt_id == PJMEDIA_FORMAT_H264 &&
+ info->pt != 0)
+ {
+ return PJ_SUCCESS;
+ }
+
+ return PJMEDIA_CODEC_EUNSUP;
+}
+
+static pj_status_t oh264_default_attr(pjmedia_vid_codec_factory *factory,
+ const pjmedia_vid_codec_info *info,
+ pjmedia_vid_codec_param *attr )
+{
+ PJ_ASSERT_RETURN(factory == &oh264_factory.base, PJ_EINVAL);
+ PJ_ASSERT_RETURN(info && attr, PJ_EINVAL);
+
+ pj_bzero(attr, sizeof(pjmedia_vid_codec_param));
+
+ attr->dir = PJMEDIA_DIR_ENCODING_DECODING;
+ attr->packing = PJMEDIA_VID_PACKING_PACKETS;
+
+ /* Encoded format */
+ pjmedia_format_init_video(&attr->enc_fmt, PJMEDIA_FORMAT_H264,
+ DEFAULT_WIDTH, DEFAULT_HEIGHT,
+ DEFAULT_FPS, 1);
+
+ /* Decoded format */
+ pjmedia_format_init_video(&attr->dec_fmt, PJMEDIA_FORMAT_I420,
+ DEFAULT_WIDTH, DEFAULT_HEIGHT,
+ DEFAULT_FPS, 1);
+
+ /* Decoding fmtp */
+ attr->dec_fmtp.cnt = 2;
+ attr->dec_fmtp.param[0].name = pj_str((char*)"profile-level-id");
+ attr->dec_fmtp.param[0].val = pj_str((char*)"42e01e");
+ attr->dec_fmtp.param[1].name = pj_str((char*)" packetization-mode");
+ attr->dec_fmtp.param[1].val = pj_str((char*)"1");
+
+ /* Bitrate */
+ attr->enc_fmt.det.vid.avg_bps = DEFAULT_AVG_BITRATE;
+ attr->enc_fmt.det.vid.max_bps = DEFAULT_MAX_BITRATE;
+
+ /* Encoding MTU */
+ attr->enc_mtu = PJMEDIA_MAX_VID_PAYLOAD_SIZE;
+
+ return PJ_SUCCESS;
+}
+
+static pj_status_t oh264_enum_info(pjmedia_vid_codec_factory *factory,
+ unsigned *count,
+ pjmedia_vid_codec_info info[])
+{
+ PJ_ASSERT_RETURN(info && *count > 0, PJ_EINVAL);
+ PJ_ASSERT_RETURN(factory == &oh264_factory.base, PJ_EINVAL);
+
+ *count = 1;
+ info->fmt_id = PJMEDIA_FORMAT_H264;
+ info->pt = PJMEDIA_RTP_PT_H264;
+ info->encoding_name = pj_str((char*)"H264");
+ info->encoding_desc = pj_str((char*)"OpenH264 codec");
+ info->clock_rate = 90000;
+ info->dir = PJMEDIA_DIR_ENCODING_DECODING;
+ info->dec_fmt_id_cnt = 1;
+ info->dec_fmt_id[0] = PJMEDIA_FORMAT_I420;
+ info->packings = PJMEDIA_VID_PACKING_PACKETS |
+ PJMEDIA_VID_PACKING_WHOLE;
+ info->fps_cnt = 3;
+ info->fps[0].num = 15;
+ info->fps[0].denum = 1;
+ info->fps[1].num = 25;
+ info->fps[1].denum = 1;
+ info->fps[2].num = 30;
+ info->fps[2].denum = 1;
+
+ return PJ_SUCCESS;
+
+}
+
+static pj_status_t oh264_alloc_codec(pjmedia_vid_codec_factory *factory,
+ const pjmedia_vid_codec_info *info,
+ pjmedia_vid_codec **p_codec)
+{
+ pj_pool_t *pool;
+ pjmedia_vid_codec *codec;
+ oh264_codec_data *oh264_data;
+ int rc;
+
+ PJ_ASSERT_RETURN(factory == &oh264_factory.base && info && p_codec,
+ PJ_EINVAL);
+
+ *p_codec = NULL;
+
+ pool = pj_pool_create(oh264_factory.pf, "oh264%p", 512, 512, NULL);
+ if (!pool)
+ return PJ_ENOMEM;
+
+ /* codec instance */
+ codec = PJ_POOL_ZALLOC_T(pool, pjmedia_vid_codec);
+ codec->factory = factory;
+ codec->op = &oh264_codec_op;
+
+ /* codec data */
+ oh264_data = PJ_POOL_ZALLOC_T(pool, oh264_codec_data);
+ oh264_data->pool = pool;
+ codec->codec_data = oh264_data;
+
+ /* encoder allocation */
+ rc = CreateSVCEncoder(&oh264_data->enc);
+ if (rc != 0)
+ goto on_error;
+
+ oh264_data->esrc_pic = PJ_POOL_ZALLOC_T(pool, SSourcePicture);
+
+ /* decoder allocation */
+ rc = CreateDecoder(&oh264_data->dec);
+ if (rc != 0)
+ goto on_error;
+
+ *p_codec = codec;
+ return PJ_SUCCESS;
+
+on_error:
+ oh264_dealloc_codec(factory, codec);
+ return PJMEDIA_CODEC_EFAILED;
+}
+
+static pj_status_t oh264_dealloc_codec(pjmedia_vid_codec_factory *factory,
+ pjmedia_vid_codec *codec )
+{
+ oh264_codec_data *oh264_data;
+
+ PJ_ASSERT_RETURN(codec, PJ_EINVAL);
+
+ oh264_data = (oh264_codec_data*) codec->codec_data;
+ if (oh264_data->enc) {
+ DestroySVCEncoder(oh264_data->enc);
+ oh264_data->enc = NULL;
+ }
+ if (oh264_data->dec) {
+ oh264_data->dec->Uninitialize();
+ DestroyDecoder(oh264_data->dec);
+ oh264_data->dec = NULL;
+ }
+ pj_pool_release(oh264_data->pool);
+ return PJ_SUCCESS;
+}
+
+static pj_status_t oh264_codec_init(pjmedia_vid_codec *codec,
+ pj_pool_t *pool )
+{
+ PJ_ASSERT_RETURN(codec && pool, PJ_EINVAL);
+ PJ_UNUSED_ARG(codec);
+ PJ_UNUSED_ARG(pool);
+ return PJ_SUCCESS;
+}
+
+static pj_status_t oh264_codec_open(pjmedia_vid_codec *codec,
+ pjmedia_vid_codec_param *codec_param )
+{
+ oh264_codec_data *oh264_data;
+ pjmedia_vid_codec_param *param;
+ pjmedia_h264_packetizer_cfg pktz_cfg;
+ pjmedia_vid_codec_h264_fmtp h264_fmtp;
+ SEncParamExt eprm;
+ SSpatialLayerConfig *elayer = &eprm.sSpatialLayers[0];
+ SLayerPEncCtx elayer_ctx;
+ SDecodingParam sDecParam = {0};
+ int rc;
+ pj_status_t status;
+
+ PJ_ASSERT_RETURN(codec && codec_param, PJ_EINVAL);
+
+ PJ_LOG(5,(THIS_FILE, "Opening codec.."));
+
+ oh264_data = (oh264_codec_data*) codec->codec_data;
+ oh264_data->prm = pjmedia_vid_codec_param_clone( oh264_data->pool,
+ codec_param);
+ param = oh264_data->prm;
+
+ /* Parse remote fmtp */
+ pj_bzero(&h264_fmtp, sizeof(h264_fmtp));
+ status = pjmedia_vid_codec_h264_parse_fmtp(&param->enc_fmtp, &h264_fmtp);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ /* Apply SDP fmtp to format in codec param */
+ if (!param->ignore_fmtp) {
+ status = pjmedia_vid_codec_h264_apply_fmtp(param);
+ if (status != PJ_SUCCESS)
+ return status;
+ }
+
+ pj_bzero(&pktz_cfg, sizeof(pktz_cfg));
+ pktz_cfg.mtu = param->enc_mtu;
+ /* Packetization mode */
+#if 0
+ if (h264_fmtp.packetization_mode == 0)
+ pktz_cfg.mode = PJMEDIA_H264_PACKETIZER_MODE_SINGLE_NAL;
+ else if (h264_fmtp.packetization_mode == 1)
+ pktz_cfg.mode = PJMEDIA_H264_PACKETIZER_MODE_NON_INTERLEAVED;
+ else
+ return PJ_ENOTSUP;
+#else
+ if (h264_fmtp.packetization_mode!=
+ PJMEDIA_H264_PACKETIZER_MODE_SINGLE_NAL &&
+ h264_fmtp.packetization_mode!=
+ PJMEDIA_H264_PACKETIZER_MODE_NON_INTERLEAVED)
+ {
+ return PJ_ENOTSUP;
+ }
+ /* Better always send in single NAL mode for better compatibility */
+ pktz_cfg.mode = PJMEDIA_H264_PACKETIZER_MODE_SINGLE_NAL;
+#endif
+
+ status = pjmedia_h264_packetizer_create(oh264_data->pool, &pktz_cfg,
+ &oh264_data->pktz);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ oh264_data->whole = (param->packing == PJMEDIA_VID_PACKING_WHOLE);
+
+ /*
+ * Encoder
+ */
+
+ /* Init encoder parameters */
+ pj_bzero(&eprm, sizeof(eprm));
+ eprm.iInputCsp = videoFormatI420;
+ eprm.sSpatialLayers[0].uiProfileIdc = 66; // PRO_BASELINE
+ eprm.iPicWidth = param->enc_fmt.det.vid.size.w;
+ eprm.iPicHeight = param->enc_fmt.det.vid.size.h;
+ eprm.fMaxFrameRate = (param->enc_fmt.det.vid.fps.num * 1.0 /
+ param->enc_fmt.det.vid.fps.denum);
+ eprm.uiFrameToBeCoded = -1;
+ eprm.iTemporalLayerNum = 1;
+ eprm.uiIntraPeriod = 0; /* I-Frame interval in frames */
+ eprm.bEnableSpsPpsIdAddition = (oh264_data->whole? false : true);
+ eprm.bEnableFrameCroppingFlag = true;
+ eprm.iLoopFilterDisableIdc = 0;
+ eprm.iLoopFilterAlphaC0Offset = 0;
+ eprm.iLoopFilterBetaOffset = 0;
+ eprm.iMultipleThreadIdc = 1;
+ eprm.bEnableRc = 1;
+ eprm.iTargetBitrate = param->enc_fmt.det.vid.avg_bps;
+ eprm.bEnableFrameSkip = 1;
+ eprm.bEnableDenoise = 0;
+ eprm.bEnableSceneChangeDetect = 1;
+ eprm.bEnableBackgroundDetection = 1;
+ eprm.bEnableAdaptiveQuant = 1;
+ eprm.bEnableLongTermReference = 0;
+ eprm.iLtrMarkPeriod = 30;
+ eprm.bPrefixNalAddingCtrl = false;
+ eprm.iSpatialLayerNum = 1;
+
+ pj_bzero(&elayer_ctx, sizeof (SLayerPEncCtx));
+ elayer_ctx.iDLayerQp = 24;
+ elayer_ctx.sSliceCfg.uiSliceMode = (oh264_data->whole ?
+ SM_SINGLE_SLICE : SM_DYN_SLICE);
+ elayer_ctx.sSliceCfg.sSliceArgument.uiSliceSizeConstraint = param->enc_mtu;
+ elayer_ctx.sSliceCfg.sSliceArgument.uiSliceNum = 1;
+ elayer_ctx.sSliceCfg.sSliceArgument.uiSliceMbNum[0] = 960;
+ elayer_ctx.sSliceCfg.sSliceArgument.uiSliceMbNum[1] = 0;
+ elayer_ctx.sSliceCfg.sSliceArgument.uiSliceMbNum[2] = 0;
+ elayer_ctx.sSliceCfg.sSliceArgument.uiSliceMbNum[3] = 0;
+ elayer_ctx.sSliceCfg.sSliceArgument.uiSliceMbNum[4] = 0;
+ elayer_ctx.sSliceCfg.sSliceArgument.uiSliceMbNum[5] = 0;
+ elayer_ctx.sSliceCfg.sSliceArgument.uiSliceMbNum[6] = 0;
+ elayer_ctx.sSliceCfg.sSliceArgument.uiSliceMbNum[7] = 0;
+
+ elayer->iVideoWidth = eprm.iPicWidth;
+ elayer->iVideoHeight = eprm.iPicHeight;
+ elayer->fFrameRate = eprm.fMaxFrameRate;
+ elayer->uiProfileIdc = eprm.sSpatialLayers[0].uiProfileIdc;
+ elayer->iSpatialBitrate = eprm.iTargetBitrate;
+ elayer->iDLayerQp = elayer_ctx.iDLayerQp;
+ elayer->sSliceCfg.uiSliceMode = elayer_ctx.sSliceCfg.uiSliceMode;
+
+ memcpy( &elayer->sSliceCfg,
+ &elayer_ctx.sSliceCfg,
+ sizeof (SSliceConfig));
+ memcpy( &elayer->sSliceCfg.sSliceArgument.uiSliceMbNum[0],
+ &elayer_ctx.sSliceCfg.sSliceArgument.uiSliceMbNum[0],
+ sizeof (elayer_ctx.sSliceCfg.sSliceArgument.uiSliceMbNum));
+
+ /* Init input picture */
+ oh264_data->esrc_pic->iColorFormat = videoFormatI420;
+ oh264_data->esrc_pic->uiTimeStamp = 0;
+ oh264_data->esrc_pic->iPicWidth = eprm.iPicWidth;
+ oh264_data->esrc_pic->iPicHeight = eprm.iPicHeight;
+ oh264_data->esrc_pic->iStride[0] = oh264_data->esrc_pic->iPicWidth;
+ oh264_data->esrc_pic->iStride[1] =
+ oh264_data->esrc_pic->iStride[2] =
+ oh264_data->esrc_pic->iStride[0]>>1;
+
+ oh264_data->enc_input_size = oh264_data->esrc_pic->iPicWidth *
+ oh264_data->esrc_pic->iPicHeight * 3 >> 1;
+
+ /* Initialize encoder */
+ rc = oh264_data->enc->InitializeExt (&eprm);
+ if (rc != cmResultSuccess) {
+ PJ_LOG(4,(THIS_FILE, "SVC encoder Initialize failed, rc=%d", rc));
+ return PJMEDIA_CODEC_EFAILED;
+ }
+
+ /*
+ * Decoder
+ */
+ sDecParam.sVideoProperty.size = sizeof (sDecParam.sVideoProperty);
+ sDecParam.iOutputColorFormat = videoFormatI420;
+ sDecParam.uiTargetDqLayer = (pj_uint8_t) - 1;
+ sDecParam.uiEcActiveFlag = 1;
+ sDecParam.sVideoProperty.eVideoBsType = VIDEO_BITSTREAM_DEFAULT;
+
+ //TODO:
+ // Apply "sprop-parameter-sets" here
+
+ rc = CreateDecoder(&oh264_data->dec);
+ if (rc) {
+ PJ_LOG(4,(THIS_FILE, "Unable to create OpenH264 decoder"));
+ return PJMEDIA_CODEC_EFAILED;
+ }
+
+ rc = oh264_data->dec->Initialize (&sDecParam);
+ if (rc) {
+ PJ_LOG(4,(THIS_FILE, "Decoder initialization failed, rc=%d", rc));
+ return PJMEDIA_CODEC_EFAILED;
+ }
+
+ int32_t color_fmt = videoFormatI420;
+ rc = oh264_data->dec->SetOption (DECODER_OPTION_DATAFORMAT, &color_fmt);
+ if (rc) {
+ PJ_LOG(4,(THIS_FILE,
+ "Warning: SetOption(DECODER_OPTION_DATAFORMAT) failed, rc=%d",
+ rc));
+ }
+
+ oh264_data->dec_buf_size = (MAX_RX_WIDTH * MAX_RX_HEIGHT * 3 >> 1) +
+ (MAX_RX_WIDTH);
+ oh264_data->dec_buf = (pj_uint8_t*)pj_pool_alloc(oh264_data->pool,
+ oh264_data->dec_buf_size);
+
+ /* Need to update param back after values are negotiated */
+ pj_memcpy(codec_param, param, sizeof(*codec_param));
+
+ return PJ_SUCCESS;
+}
+
+static pj_status_t oh264_codec_close(pjmedia_vid_codec *codec)
+{
+ PJ_ASSERT_RETURN(codec, PJ_EINVAL);
+ PJ_UNUSED_ARG(codec);
+ return PJ_SUCCESS;
+}
+
+static pj_status_t oh264_codec_modify(pjmedia_vid_codec *codec,
+ const pjmedia_vid_codec_param *param)
+{
+ PJ_ASSERT_RETURN(codec && param, PJ_EINVAL);
+ PJ_UNUSED_ARG(codec);
+ PJ_UNUSED_ARG(param);
+ return PJ_EINVALIDOP;
+}
+
+static pj_status_t oh264_codec_get_param(pjmedia_vid_codec *codec,
+ pjmedia_vid_codec_param *param)
+{
+ struct oh264_codec_data *oh264_data;
+
+ PJ_ASSERT_RETURN(codec && param, PJ_EINVAL);
+
+ oh264_data = (oh264_codec_data*) codec->codec_data;
+ pj_memcpy(param, oh264_data->prm, sizeof(*param));
+
+ return PJ_SUCCESS;
+}
+
+static pj_status_t oh264_codec_encode_begin(pjmedia_vid_codec *codec,
+ const pjmedia_vid_encode_opt *opt,
+ const pjmedia_frame *input,
+ unsigned out_size,
+ pjmedia_frame *output,
+ pj_bool_t *has_more)
+{
+ struct oh264_codec_data *oh264_data;
+ int rc;
+
+ PJ_ASSERT_RETURN(codec && input && out_size && output && has_more,
+ PJ_EINVAL);
+
+ oh264_data = (oh264_codec_data*) codec->codec_data;
+
+ PJ_ASSERT_RETURN(input->size == oh264_data->enc_input_size,
+ PJMEDIA_CODEC_EFRMINLEN);
+
+ if (opt && opt->force_keyframe) {
+ oh264_data->enc->ForceIntraFrame(true);
+ }
+
+ oh264_data->esrc_pic->pData[0] = (pj_uint8_t*)input->buf;
+ oh264_data->esrc_pic->pData[1] = oh264_data->esrc_pic->pData[0] +
+ (oh264_data->esrc_pic->iPicWidth *
+ oh264_data->esrc_pic->iPicHeight);
+ oh264_data->esrc_pic->pData[2] = oh264_data->esrc_pic->pData[1] +
+ (oh264_data->esrc_pic->iPicWidth *
+ oh264_data->esrc_pic->iPicHeight >>2);
+
+ pj_memset (&oh264_data->bsi, 0, sizeof (SFrameBSInfo));
+ rc = oh264_data->enc->EncodeFrame( oh264_data->esrc_pic, &oh264_data->bsi);
+ if (rc != cmResultSuccess) {
+ PJ_LOG(5,(THIS_FILE, "EncodeFrame() error, ret: %d", rc));
+ return PJMEDIA_CODEC_EFAILED;
+ }
+
+ if (oh264_data->bsi.eOutputFrameType == videoFrameTypeSkip) {
+ output->size = 0;
+ output->type = PJMEDIA_FRAME_TYPE_NONE;
+ output->timestamp = input->timestamp;
+ return PJ_SUCCESS;
+ }
+
+ oh264_data->ets = input->timestamp;
+ oh264_data->ilayer = 0;
+ oh264_data->enc_frame_size = oh264_data->enc_processed = 0;
+
+ if (oh264_data->whole) {
+ SLayerBSInfo* pLayerBsInfo;
+ pj_uint8_t *payload;
+ unsigned i, payload_size = 0;
+
+ *has_more = PJ_FALSE;
+
+ /* Find which layer with biggest payload */
+ oh264_data->ilayer = 0;
+ payload_size = oh264_data->bsi.sLayerInfo[0].iNalLengthInByte[0];
+ for (i=0; i < (unsigned)oh264_data->bsi.iLayerNum; ++i) {
+ unsigned j;
+ pLayerBsInfo = &oh264_data->bsi.sLayerInfo[i];
+ for (j=0; j < (unsigned)pLayerBsInfo->iNalCount; ++j) {
+ if (pLayerBsInfo->iNalLengthInByte[j] > (int)payload_size) {
+ payload_size = pLayerBsInfo->iNalLengthInByte[j];
+ oh264_data->ilayer = i;
+ }
+ }
+ }
+
+ pLayerBsInfo = &oh264_data->bsi.sLayerInfo[oh264_data->ilayer];
+ if (pLayerBsInfo == NULL) {
+ output->size = 0;
+ output->type = PJMEDIA_FRAME_TYPE_NONE;
+ return PJ_SUCCESS;
+ }
+
+ payload = pLayerBsInfo->pBsBuf;
+ payload_size = 0;
+ for (int inal = pLayerBsInfo->iNalCount - 1; inal >= 0; --inal) {
+ payload_size += pLayerBsInfo->iNalLengthInByte[inal];
+ }
+
+ if (payload_size > out_size)
+ return PJMEDIA_CODEC_EFRMTOOSHORT;
+
+ output->type = PJMEDIA_FRAME_TYPE_VIDEO;
+ output->size = payload_size;
+ output->timestamp = input->timestamp;
+ pj_memcpy(output->buf, payload, payload_size);
+
+ return PJ_SUCCESS;
+ }
+
+ return oh264_codec_encode_more(codec, out_size, output, has_more);
+}
+
+
+static pj_status_t oh264_codec_encode_more(pjmedia_vid_codec *codec,
+ unsigned out_size,
+ pjmedia_frame *output,
+ pj_bool_t *has_more)
+{
+ struct oh264_codec_data *oh264_data;
+ const pj_uint8_t *payload;
+ pj_size_t payload_len;
+ pj_status_t status;
+
+ PJ_ASSERT_RETURN(codec && out_size && output && has_more,
+ PJ_EINVAL);
+
+ oh264_data = (oh264_codec_data*) codec->codec_data;
+
+ if (oh264_data->enc_processed < oh264_data->enc_frame_size) {
+ /* We have outstanding frame in packetizer */
+ status = pjmedia_h264_packetize(oh264_data->pktz,
+ oh264_data->enc_frame_whole,
+ oh264_data->enc_frame_size,
+ &oh264_data->enc_processed,
+ &payload, &payload_len);
+ if (status != PJ_SUCCESS) {
+ /* Reset */
+ oh264_data->enc_frame_size = oh264_data->enc_processed = 0;
+ *has_more = (oh264_data->enc_processed <
+ oh264_data->enc_frame_size) ||
+ (oh264_data->ilayer < oh264_data->bsi.iLayerNum);
+
+ PJ_PERROR(3,(THIS_FILE, status, "pjmedia_h264_packetize() error"));
+ return status;
+ }
+
+ PJ_ASSERT_RETURN(payload_len <= out_size, PJMEDIA_CODEC_EFRMTOOSHORT);
+
+ output->type = PJMEDIA_FRAME_TYPE_VIDEO;
+ pj_memcpy(output->buf, payload, payload_len);
+ output->size = payload_len;
+
+ if (oh264_data->bsi.eOutputFrameType == videoFrameTypeIDR) {
+ output->bit_info |= PJMEDIA_VID_FRM_KEYFRAME;
+ }
+
+ *has_more = (oh264_data->enc_processed < oh264_data->enc_frame_size) ||
+ (oh264_data->ilayer < oh264_data->bsi.iLayerNum);
+ return PJ_SUCCESS;
+ }
+
+ if (oh264_data->ilayer >= oh264_data->bsi.iLayerNum) {
+ /* No more unretrieved frame */
+ goto no_frame;
+ }
+
+ SLayerBSInfo* pLayerBsInfo;
+ pLayerBsInfo = &oh264_data->bsi.sLayerInfo[oh264_data->ilayer++];
+ if (pLayerBsInfo == NULL) {
+ goto no_frame;
+ }
+
+ oh264_data->enc_frame_size = 0;
+ for (int inal = pLayerBsInfo->iNalCount - 1; inal >= 0; --inal) {
+ oh264_data->enc_frame_size += pLayerBsInfo->iNalLengthInByte[inal];
+ }
+
+ oh264_data->enc_frame_whole = pLayerBsInfo->pBsBuf;
+ oh264_data->enc_processed = 0;
+
+
+ status = pjmedia_h264_packetize(oh264_data->pktz,
+ oh264_data->enc_frame_whole,
+ oh264_data->enc_frame_size,
+ &oh264_data->enc_processed,
+ &payload, &payload_len);
+ if (status != PJ_SUCCESS) {
+ /* Reset */
+ oh264_data->enc_frame_size = oh264_data->enc_processed = 0;
+ *has_more = (oh264_data->ilayer < oh264_data->bsi.iLayerNum);
+
+ PJ_PERROR(3,(THIS_FILE, status, "pjmedia_h264_packetize() error [2]"));
+ return status;
+ }
+
+ PJ_ASSERT_RETURN(payload_len <= out_size, PJMEDIA_CODEC_EFRMTOOSHORT);
+
+ output->type = PJMEDIA_FRAME_TYPE_VIDEO;
+ pj_memcpy(output->buf, payload, payload_len);
+ output->size = payload_len;
+
+ if (oh264_data->bsi.eOutputFrameType == videoFrameTypeIDR) {
+ output->bit_info |= PJMEDIA_VID_FRM_KEYFRAME;
+ }
+
+ *has_more = (oh264_data->enc_processed < oh264_data->enc_frame_size) ||
+ (oh264_data->ilayer < oh264_data->bsi.iLayerNum);
+
+ return PJ_SUCCESS;
+
+no_frame:
+ *has_more = PJ_FALSE;
+ output->size = 0;
+ output->type = PJMEDIA_FRAME_TYPE_NONE;
+ return PJ_SUCCESS;
+}
+
+static int write_yuv(pj_uint8_t *buf,
+ unsigned dst_len,
+ unsigned char* pData[3],
+ int iStride[2],
+ int iWidth,
+ int iHeight)
+{
+ unsigned req_size;
+ pj_uint8_t *dst = buf;
+ pj_uint8_t *max = dst + dst_len;
+ int i;
+ unsigned char* pPtr = NULL;
+
+ req_size = (iWidth * iHeight) + (iWidth / 2 * iHeight / 2) +
+ (iWidth / 2 * iHeight / 2);
+ if (dst_len < req_size)
+ return -1;
+
+ pPtr = pData[0];
+ for (i = 0; i < iHeight && (dst + iWidth < max); i++) {
+ pj_memcpy(dst, pPtr, iWidth);
+ pPtr += iStride[0];
+ dst += iWidth;
+ }
+
+ if (i < iHeight)
+ return -1;
+
+ iHeight = iHeight / 2;
+ iWidth = iWidth / 2;
+ pPtr = pData[1];
+ for (i = 0; i < iHeight && (dst + iWidth <= max); i++) {
+ pj_memcpy(dst, pPtr, iWidth);
+ pPtr += iStride[1];
+ dst += iWidth;
+ }
+
+ if (i < iHeight)
+ return -1;
+
+ pPtr = pData[2];
+ for (i = 0; i < iHeight && (dst + iWidth <= max); i++) {
+ pj_memcpy(dst, pPtr, iWidth);
+ pPtr += iStride[1];
+ dst += iWidth;
+ }
+
+ if (i < iHeight)
+ return -1;
+
+ return dst - buf;
+}
+
+static pj_status_t oh264_got_decoded_frame(pjmedia_vid_codec *codec,
+ struct oh264_codec_data *oh264_data,
+ void *pData[3],
+ SBufferInfo *sDstBufInfo,
+ pj_timestamp *timestamp,
+ unsigned out_size,
+ pjmedia_frame *output)
+{
+ pj_uint8_t* pDst[3] = {NULL};
+
+ pDst[0] = (pj_uint8_t*)pData[0];
+ pDst[1] = (pj_uint8_t*)pData[1];
+ pDst[2] = (pj_uint8_t*)pData[2];
+
+ /* Do not reset size as it may already contain frame
+ output->size = 0;
+ */
+
+ if (!pDst[0] || !pDst[1] || !pDst[2]) {
+ return PJ_SUCCESS;
+ }
+
+ int iStride[2];
+ int iWidth = sDstBufInfo->UsrData.sSystemBuffer.iWidth;
+ int iHeight = sDstBufInfo->UsrData.sSystemBuffer.iHeight;
+
+ iStride[0] = sDstBufInfo->UsrData.sSystemBuffer.iStride[0];
+ iStride[1] = sDstBufInfo->UsrData.sSystemBuffer.iStride[1];
+
+ int len = write_yuv((pj_uint8_t *)output->buf, out_size,
+ pDst, iStride, iWidth, iHeight);
+ if (len > 0) {
+ output->timestamp = *timestamp;
+ output->size = len;
+ output->type = PJMEDIA_FRAME_TYPE_VIDEO;
+ } else {
+ /* buffer is damaged, reset size */
+ output->size = 0;
+ return PJMEDIA_CODEC_EFRMTOOSHORT;
+ }
+
+ /* Detect format change */
+ if (iWidth != (int)oh264_data->prm->dec_fmt.det.vid.size.w ||
+ iHeight != (int)oh264_data->prm->dec_fmt.det.vid.size.h)
+ {
+ pjmedia_event event;
+
+ PJ_LOG(4,(THIS_FILE, "Frame size changed: %dx%d --> %dx%d",
+ oh264_data->prm->dec_fmt.det.vid.size.w,
+ oh264_data->prm->dec_fmt.det.vid.size.h,
+ iWidth, iHeight));
+
+ oh264_data->prm->dec_fmt.det.vid.size.w = iWidth;
+ oh264_data->prm->dec_fmt.det.vid.size.h = iHeight;
+
+ /* Broadcast format changed event */
+ pjmedia_event_init(&event, PJMEDIA_EVENT_FMT_CHANGED,
+ timestamp, codec);
+ event.data.fmt_changed.dir = PJMEDIA_DIR_DECODING;
+ pjmedia_format_copy(&event.data.fmt_changed.new_fmt,
+ &oh264_data->prm->dec_fmt);
+ pjmedia_event_publish(NULL, codec, &event,
+ PJMEDIA_EVENT_PUBLISH_DEFAULT);
+ }
+
+ return PJ_SUCCESS;
+}
+
+static pj_status_t oh264_codec_decode(pjmedia_vid_codec *codec,
+ pj_size_t count,
+ pjmedia_frame packets[],
+ unsigned out_size,
+ pjmedia_frame *output)
+{
+ struct oh264_codec_data *oh264_data;
+ void* pData[3] = {NULL};
+ const pj_uint8_t nal_start[] = { 0, 0, 1 };
+ SBufferInfo sDstBufInfo;
+ pj_bool_t has_frame = PJ_FALSE;
+ unsigned buf_pos, whole_len = 0;
+ unsigned i, frm_cnt;
+ pj_status_t status = PJ_SUCCESS;
+
+ PJ_ASSERT_RETURN(codec && count && packets && out_size && output,
+ PJ_EINVAL);
+ PJ_ASSERT_RETURN(output->buf, PJ_EINVAL);
+
+ oh264_data = (oh264_codec_data*) codec->codec_data;
+
+ /*
+ * Step 1: unpacketize the packets/frames
+ */
+ whole_len = 0;
+ if (oh264_data->whole) {
+ for (i=0; i<count; ++i) {
+ if (whole_len + packets[i].size > oh264_data->dec_buf_size) {
+ PJ_LOG(4,(THIS_FILE, "Decoding buffer overflow [1]"));
+ return PJMEDIA_CODEC_EFRMTOOSHORT;
+ }
+
+ pj_memcpy( oh264_data->dec_buf + whole_len,
+ (pj_uint8_t*)packets[i].buf,
+ packets[i].size);
+ whole_len += packets[i].size;
+ }
+
+ } else {
+ for (i=0; i<count; ++i) {
+
+ if (whole_len + packets[i].size + sizeof(nal_start) >
+ oh264_data->dec_buf_size)
+ {
+ PJ_LOG(4,(THIS_FILE, "Decoding buffer overflow [1]"));
+ return PJMEDIA_CODEC_EFRMTOOSHORT;
+ }
+
+ status = pjmedia_h264_unpacketize( oh264_data->pktz,
+ (pj_uint8_t*)packets[i].buf,
+ packets[i].size,
+ oh264_data->dec_buf,
+ oh264_data->dec_buf_size,
+ &whole_len);
+ if (status != PJ_SUCCESS) {
+ PJ_PERROR(4,(THIS_FILE, status, "Unpacketize error"));
+ continue;
+ }
+ }
+ }
+
+ if (whole_len + sizeof(nal_start) > oh264_data->dec_buf_size) {
+ PJ_LOG(4,(THIS_FILE, "Decoding buffer overflow [2]"));
+ return PJMEDIA_CODEC_EFRMTOOSHORT;
+ }
+
+ /* Dummy NAL sentinel */
+ pj_memcpy( oh264_data->dec_buf + whole_len, nal_start, sizeof(nal_start));
+
+ /*
+ * Step 2: parse the individual NAL and give to decoder
+ */
+ buf_pos = 0;
+ for ( frm_cnt=0; ; ++frm_cnt) {
+ unsigned frm_size;
+ unsigned char *start;
+
+ for (i = 0; buf_pos + i < whole_len; i++) {
+ if (oh264_data->dec_buf[buf_pos + i] == 0 &&
+ oh264_data->dec_buf[buf_pos + i + 1] == 0 &&
+ oh264_data->dec_buf[buf_pos + i + 2] == 1 &&
+ i > 1)
+ {
+ break;
+ }
+ }
+ frm_size = i;
+
+ pj_bzero( pData, sizeof(pData));
+ pj_bzero( &sDstBufInfo, sizeof (SBufferInfo));
+
+ start = oh264_data->dec_buf + buf_pos;
+
+ /* Decode */
+ oh264_data->dec->DecodeFrame2( start, frm_size, pData, &sDstBufInfo);
+
+ if (sDstBufInfo.iBufferStatus == 1) {
+ /* May overwrite existing frame but that's ok. */
+ status = oh264_got_decoded_frame(codec, oh264_data, pData,
+ &sDstBufInfo,
+ &packets[0].timestamp, out_size,
+ output);
+ has_frame = (status==PJ_SUCCESS && output->size != 0);
+ }
+
+ if (buf_pos + frm_size >= whole_len)
+ break;
+
+ buf_pos += frm_size;
+ }
+
+ /* Signal that we have no more frames */
+ int32_t iEndOfStreamFlag;
+ iEndOfStreamFlag = true;
+ oh264_data->dec->SetOption( DECODER_OPTION_END_OF_STREAM,
+ (void*)&iEndOfStreamFlag);
+
+ /* Retrieve the decoded frame */
+ pj_bzero(pData, sizeof(pData));
+ pj_bzero(&sDstBufInfo, sizeof (SBufferInfo));
+ oh264_data->dec->DecodeFrame2 (NULL, 0, pData, &sDstBufInfo);
+
+ if (sDstBufInfo.iBufferStatus == 1) {
+ /* Overwrite existing output frame and that's ok, because we assume
+ * newer frame have better quality because it has more NALs
+ */
+ status = oh264_got_decoded_frame(codec, oh264_data, pData,
+ &sDstBufInfo, &packets[0].timestamp,
+ out_size, output);
+ has_frame = (status==PJ_SUCCESS && output->size != 0);
+ }
+
+ if (!has_frame) {
+ pjmedia_event event;
+
+ /* Broadcast missing keyframe event */
+ pjmedia_event_init(&event, PJMEDIA_EVENT_KEYFRAME_MISSING,
+ &packets[0].timestamp, codec);
+ pjmedia_event_publish(NULL, codec, &event,
+ PJMEDIA_EVENT_PUBLISH_DEFAULT);
+
+ PJ_LOG(5,(THIS_FILE, "Decode couldn't produce picture, "
+ "input nframes=%d, concatenated size=%d bytes",
+ count, whole_len));
+
+ output->type = PJMEDIA_FRAME_TYPE_NONE;
+ output->size = 0;
+ output->timestamp = packets[0].timestamp;
+ }
+
+ return status;
+}
+
+#endif /* PJMEDIA_HAS_OPENH264_CODEC */
diff --git a/pjmedia/src/pjmedia/vid_codec_util.c b/pjmedia/src/pjmedia/vid_codec_util.c
index 75cbc8b3..c5b5abdc 100644
--- a/pjmedia/src/pjmedia/vid_codec_util.c
+++ b/pjmedia/src/pjmedia/vid_codec_util.c
@@ -631,7 +631,7 @@ static pj_status_t find_highest_res(pjmedia_vid_codec_h264_fmtp *fmtp,
}
/* Calculate maximum size (in macroblocks) */
- max_fs = fmtp->max_mbps * fps->denum / fps->num;
+ max_fs = fmtp->max_mbps * the_fps.denum / the_fps.num;
max_fs = PJ_MIN(max_fs, fmtp->max_fs);
/* Check if the specified ratio is using big numbers
diff --git a/pjmedia/src/test/vid_codec_test.c b/pjmedia/src/test/vid_codec_test.c
index f613b84d..b0b2abc2 100644
--- a/pjmedia/src/test/vid_codec_test.c
+++ b/pjmedia/src/test/vid_codec_test.c
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "test.h"
-#include <pjmedia-codec/ffmpeg_vid_codecs.h>
+#include <pjmedia-codec.h>
#include <pjmedia-videodev/videodev.h>
#include <pjmedia/vid_codec.h>
#include <pjmedia/port.h>
@@ -297,6 +297,9 @@ static int encode_decode_test(pj_pool_t *pool, const char *codec_id,
codec_param.packing = packing;
+ /* Don't apply SDP fmtp */
+ codec_param.ignore_fmtp = PJ_TRUE;
+
/* Open codec */
status = pjmedia_vid_codec_mgr_alloc_codec(NULL, codec_info,
&codec);
@@ -453,6 +456,13 @@ int vid_codec_test(void)
if (status != PJ_SUCCESS)
return -10;
+#if PJMEDIA_HAS_VIDEO && PJMEDIA_HAS_OPENH264_CODEC
+ status = pjmedia_codec_openh264_vid_init(NULL, mem);
+ if (status != PJ_SUCCESS) {
+ return -22;
+ }
+#endif
+
#if PJMEDIA_HAS_FFMPEG_VID_CODEC
status = pjmedia_codec_ffmpeg_vid_init(NULL, mem);
if (status != PJ_SUCCESS)
@@ -463,6 +473,7 @@ int vid_codec_test(void)
if (rc != 0)
goto on_return;
+#if PJMEDIA_HAS_FFMPEG_VID_CODEC
rc = encode_decode_test(pool, "h263-1998", PJMEDIA_VID_PACKING_WHOLE);
if (rc != 0)
goto on_return;
@@ -470,11 +481,26 @@ int vid_codec_test(void)
rc = encode_decode_test(pool, "h263-1998", PJMEDIA_VID_PACKING_PACKETS);
if (rc != 0)
goto on_return;
+#endif
+
+#if PJMEDIA_HAS_FFMPEG_VID_CODEC || PJMEDIA_HAS_OPENH264_CODEC
+ rc = encode_decode_test(pool, "h264", PJMEDIA_VID_PACKING_WHOLE);
+ if (rc != 0)
+ goto on_return;
+
+ rc = encode_decode_test(pool, "h264", PJMEDIA_VID_PACKING_PACKETS);
+ if (rc != 0)
+ goto on_return;
+#endif
+
on_return:
#if PJMEDIA_HAS_FFMPEG_VID_CODEC
pjmedia_codec_ffmpeg_vid_deinit();
#endif
+#if defined(PJMEDIA_HAS_OPENH264_CODEC) && PJMEDIA_HAS_OPENH264_CODEC != 0
+ pjmedia_codec_openh264_vid_deinit();
+#endif
pjmedia_vid_dev_subsys_shutdown();
pj_pool_release(pool);
pj_log_set_level(orig_log_level);
diff --git a/pjsip-apps/build/Samples.mak b/pjsip-apps/build/Samples.mak
index 6ec7f191..d8769ff1 100644
--- a/pjsip-apps/build/Samples.mak
+++ b/pjsip-apps/build/Samples.mak
@@ -45,6 +45,7 @@ SAMPLES := auddemo \
streamutil \
strerror \
tonegen \
+ vid_codec_test \
vid_streamutil
PJSUA2_SAMPLES := pjsua2_demo
diff --git a/pjsip-apps/src/samples/aviplay.c b/pjsip-apps/src/samples/aviplay.c
index 35b05044..40dfaf90 100644
--- a/pjsip-apps/src/samples/aviplay.c
+++ b/pjsip-apps/src/samples/aviplay.c
@@ -500,6 +500,12 @@ static int main_func(int argc, char *argv[])
goto on_return;
}
+#if defined(PJMEDIA_HAS_OPENH264_CODEC) && PJMEDIA_HAS_OPENH264_CODEC != 0
+ status = pjmedia_codec_openh264_vid_init(NULL, &cp.factory);
+ if (status != PJ_SUCCESS)
+ goto on_return;
+#endif
+
#if PJMEDIA_HAS_FFMPEG_VID_CODEC
status = pjmedia_codec_ffmpeg_vid_init(NULL, &cp.factory);
if (status != PJ_SUCCESS)
@@ -521,6 +527,9 @@ on_return:
#if PJMEDIA_HAS_FFMPEG_VID_CODEC
pjmedia_codec_ffmpeg_vid_deinit();
#endif
+#if defined(PJMEDIA_HAS_OPENH264_CODEC) && PJMEDIA_HAS_OPENH264_CODEC != 0
+ pjmedia_codec_openh264_vid_deinit();
+#endif
pjmedia_aud_subsys_shutdown();
pjmedia_vid_dev_subsys_shutdown();
diff --git a/pjsip-apps/src/samples/simpleua.c b/pjsip-apps/src/samples/simpleua.c
index 68c50b9b..b7f10250 100644
--- a/pjsip-apps/src/samples/simpleua.c
+++ b/pjsip-apps/src/samples/simpleua.c
@@ -385,6 +385,11 @@ int main(int argc, char *argv[])
status = pjmedia_vid_dev_subsys_init(&cp.factory);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
+# if defined(PJMEDIA_HAS_OPENH264_CODEC) && PJMEDIA_HAS_OPENH264_CODEC != 0
+ status = pjmedia_codec_openh264_vid_init(NULL, &cp.factory);
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
+# endif
+
# if defined(PJMEDIA_HAS_FFMPEG_VID_CODEC) && PJMEDIA_HAS_FFMPEG_VID_CODEC!=0
/* Init ffmpeg video codecs */
status = pjmedia_codec_ffmpeg_vid_init(NULL, &cp.factory);
@@ -576,6 +581,9 @@ int main(int argc, char *argv[])
# if defined(PJMEDIA_HAS_FFMPEG_VID_CODEC) && PJMEDIA_HAS_FFMPEG_VID_CODEC!=0
pjmedia_codec_ffmpeg_vid_deinit();
# endif
+# if defined(PJMEDIA_HAS_OPENH264_CODEC) && PJMEDIA_HAS_OPENH264_CODEC != 0
+ pjmedia_codec_openh264_vid_deinit();
+# endif
#endif
diff --git a/pjsip-apps/src/samples/vid_codec_test.c b/pjsip-apps/src/samples/vid_codec_test.c
new file mode 100644
index 00000000..a249c71f
--- /dev/null
+++ b/pjsip-apps/src/samples/vid_codec_test.c
@@ -0,0 +1,521 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2014 Teluu Inc. (http://www.teluu.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+/**
+ * \page page_pjmedia_samples_vid_codec_test_c Samples: Video Codec Test
+ *
+ * Video codec encode and decode test.
+ *
+ * This file is pjsip-apps/src/samples/vid_vodec_test.c
+ *
+ * \includelineno vid_vodec_test.c
+ */
+
+#include <pjlib.h>
+#include <pjlib-util.h>
+#include <pjmedia.h>
+#include <pjmedia-codec.h>
+
+
+#if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
+
+
+#include <stdlib.h> /* atoi() */
+#include <stdio.h>
+
+#include "util.h"
+
+
+static const char *desc =
+ " vid_vodec_test \n"
+;
+
+#define THIS_FILE "vid_vodec_test.c"
+
+
+/* If set, local renderer will be created to play original file */
+#define HAS_LOCAL_RENDERER_FOR_PLAY_FILE 1
+
+
+/* Default width and height for the renderer, better be set to maximum
+ * acceptable size.
+ */
+#define DEF_RENDERER_WIDTH 640
+#define DEF_RENDERER_HEIGHT 480
+
+
+/* Prototype */
+static void print_stream_stat(pjmedia_vid_stream *stream,
+ const pjmedia_vid_codec_param *codec_param);
+
+/* Prototype for LIBSRTP utility in file datatypes.c */
+int hex_string_to_octet_string(char *raw, char *hex, int len);
+
+/*
+ * Register all codecs.
+ */
+static pj_status_t init_codecs(pj_pool_factory *pf)
+{
+ pj_status_t status;
+
+ /* To suppress warning about unused var when all codecs are disabled */
+ PJ_UNUSED_ARG(status);
+
+#if defined(PJMEDIA_HAS_OPENH264_CODEC) && PJMEDIA_HAS_OPENH264_CODEC != 0
+ status = pjmedia_codec_openh264_vid_init(NULL, pf);
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
+#endif
+
+#if defined(PJMEDIA_HAS_FFMPEG_VID_CODEC) && PJMEDIA_HAS_FFMPEG_VID_CODEC != 0
+ status = pjmedia_codec_ffmpeg_vid_init(NULL, pf);
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
+#endif
+
+ return PJ_SUCCESS;
+}
+
+/*
+ * Register all codecs.
+ */
+static void deinit_codecs()
+{
+#if defined(PJMEDIA_HAS_FFMPEG_VID_CODEC) && PJMEDIA_HAS_FFMPEG_VID_CODEC != 0
+ pjmedia_codec_ffmpeg_vid_deinit();
+#endif
+
+#if defined(PJMEDIA_HAS_OPENH264_CODEC) && PJMEDIA_HAS_OPENH264_CODEC != 0
+ pjmedia_codec_openh264_vid_deinit();
+#endif
+
+}
+
+/*
+ * usage()
+ */
+static void usage()
+{
+ puts(desc);
+}
+
+static void show_diff(const pj_uint8_t *buf1, const pj_uint8_t *buf2,
+ unsigned size)
+{
+ enum {
+ STEP = 50
+ };
+ unsigned i=0;
+
+ for (; i<size; ) {
+ const pj_uint8_t *p1 = buf1 + i, *p2 = buf2 + i;
+ unsigned j;
+
+ printf("%8d ", i);
+ for (j=0; j<STEP && i+j<size; ++j) {
+ printf(" %02x", *(p1+j));
+ }
+ printf("\n");
+ printf(" ");
+ for (j=0; j<STEP && i+j<size; ++j) {
+ if (*(p1+j) == *(p2+j)) {
+ printf(" %02x", *(p2+j));
+ } else {
+ printf(" %02x", *(p2+j));
+ }
+ }
+ printf("\n");
+
+ i += j;
+ }
+}
+
+static void diff_file()
+{
+ const char *filename[2] = {
+ "/home/bennylp/Desktop/opt/src/openh264-svn/testbin/test.264",
+ "/home/bennylp/Desktop/opt/src/openh264-svn/testbin/test2.264"
+ };
+ unsigned size[2];
+ pj_uint8_t *buf[2], start_nal[3] = {0, 0, 1};
+ unsigned i, pos[2], frame_cnt, mismatch_cnt=0;
+
+ for (i=0; i<2; ++i) {
+ FILE *fhnd;
+ const pj_uint8_t start_nal[] = { 0, 0, 1};
+
+ fhnd = fopen(filename[i], "rb");
+ if (!fhnd) {
+ printf("Error opening %s\n", filename[i]);
+ return;
+ }
+
+ fseek(fhnd, 0, SEEK_END);
+ size[i] = ftell(fhnd);
+ fseek(fhnd, 0, SEEK_SET);
+
+ buf[i] = (pj_uint8_t*)malloc(size[i] + 4);
+ if (!buf[i])
+ return;
+
+ if (fread (buf[i], 1, size[i], fhnd) != (unsigned)size[i]) {
+ fprintf (stderr, "Unable to read whole file\n");
+ return;
+ }
+
+ memcpy (buf[i] + size[i], start_nal, sizeof(start_nal));
+
+ fclose(fhnd);
+ }
+
+ if (size[0] != size[1]) {
+ printf("File size mismatch\n");
+ return;
+ }
+
+ pos[0] = pos[1] = 0;
+ for ( frame_cnt=0; ; ++frame_cnt) {
+ unsigned nal_len[2];
+ for (i = 0; i < size[0]; i++) {
+ if (memcmp(buf[0] + pos[0] + i, start_nal,
+ sizeof(start_nal)) == 0 && i > 0)
+ {
+ break;
+ }
+ }
+ nal_len[0] = i;
+ for (i = 0; i < size[1]; i++) {
+ if (memcmp(buf[1] + pos[1] + i, start_nal,
+ sizeof(start_nal)) == 0 && i > 0)
+ {
+ break;
+ }
+ }
+ nal_len[1] = i;
+
+ if (nal_len[0] != nal_len[1]) {
+ printf("Different size in frame %d (%d vs %d)\n",
+ frame_cnt, nal_len[0], nal_len[1]);
+ }
+
+ if (memcmp(buf[0]+pos[0], buf[1]+pos[1], nal_len[0]) != 0) {
+ printf("Mismatch in frame %d\n", frame_cnt);
+ show_diff(buf[0]+pos[0], buf[1]+pos[1], nal_len[0]);
+ puts("");
+ ++mismatch_cnt;
+ }
+
+ pos[0] += nal_len[0];
+ pos[1] += nal_len[1];
+
+ if (pos[0] >= size[0])
+ break;
+ }
+
+ free(buf[0]);
+ free(buf[1]);
+
+ if (!mismatch_cnt)
+ puts("Files the same!");
+ else
+ printf("%d mismatches\n", mismatch_cnt);
+}
+
+/*
+ * main()
+ */
+int main(int argc, char *argv[])
+{
+ pj_caching_pool cp;
+ pjmedia_endpt *med_endpt;
+ pj_pool_t *pool;
+ pj_status_t status;
+
+ /* Codec */
+ char *codec_id = (char*)"H264";
+ const pjmedia_vid_codec_info *codec_info;
+ pjmedia_vid_codec_param codec_param;
+ pjmedia_vid_codec *codec = NULL;
+
+ //const char *save_filename =
+ // "/home/bennylp/Desktop/opt/src/openh264-svn/testbin/test.264";
+ const char *save_filename = NULL;
+
+ /* File */
+ enum
+ {
+ WIDTH = 320,
+ HEIGHT = 192,
+ FPS = 12,
+ YUV_SIZE = WIDTH * HEIGHT * 3 >> 1,
+ YUV_BUF_SIZE = YUV_SIZE + WIDTH,
+ MAX_FRAMES = 32,
+ MTU = 1500
+ };
+ FILE *fyuv = NULL;
+ FILE *f264 = NULL;
+ typedef pj_uint8_t enc_buf_type[MTU];
+ pj_uint8_t yuv_frame[YUV_BUF_SIZE];
+ enc_buf_type enc_buf[MAX_FRAMES];
+ unsigned read_cnt = 0,
+ pkt_cnt = 0,
+ dec_cnt = 0,
+ enc_cnt;
+
+ if (0) {
+ diff_file();
+ return 1;
+ }
+
+ /* init PJLIB : */
+ status = pj_init();
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
+
+ /* Must create a pool factory before we can allocate any memory. */
+ pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);
+
+ /* Initialize media endpoint. */
+ status = pjmedia_endpt_create(&cp.factory, NULL, 1, &med_endpt);
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
+
+ /* Create memory pool for application purpose */
+ pool = pj_pool_create( &cp.factory, /* pool factory */
+ "app", /* pool name. */
+ 4000, /* init size */
+ 4000, /* increment size */
+ NULL /* callback on error */
+ );
+
+ /* Init video format manager */
+ pjmedia_video_format_mgr_create(pool, 64, 0, NULL);
+
+ /* Init video converter manager */
+ pjmedia_converter_mgr_create(pool, NULL);
+
+ /* Init event manager */
+ pjmedia_event_mgr_create(pool, 0, NULL);
+
+ /* Init video codec manager */
+ pjmedia_vid_codec_mgr_create(pool, NULL);
+
+ /* Register all supported codecs */
+ status = init_codecs(&cp.factory);
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
+
+ /* Open YUV file */
+ fyuv = fopen("pjsip-apps/bin/CiscoVT2people_320x192_12fps.yuv", "rb");
+ if (!fyuv) {
+ puts("Unable to open ../CiscoVT2people_320x192_12fps.yuv");
+ status = -1;
+ goto on_exit;
+ }
+
+ /* Write 264 file if wanted */
+ if (save_filename) {
+ f264 = fopen(save_filename, "wb");
+ }
+
+ /* Find which codec to use. */
+ if (codec_id) {
+ unsigned count = 1;
+ pj_str_t str_codec_id = pj_str(codec_id);
+
+ status = pjmedia_vid_codec_mgr_find_codecs_by_id(NULL,
+ &str_codec_id, &count,
+ &codec_info, NULL);
+ if (status != PJ_SUCCESS) {
+ printf("Error: unable to find codec %s\n", codec_id);
+ return 1;
+ }
+ } else {
+ static pjmedia_vid_codec_info info[1];
+ unsigned count = PJ_ARRAY_SIZE(info);
+
+ /* Default to first codec */
+ pjmedia_vid_codec_mgr_enum_codecs(NULL, &count, info, NULL);
+ codec_info = &info[0];
+ }
+
+ /* Get codec default param for info */
+ status = pjmedia_vid_codec_mgr_get_default_param(NULL, codec_info,
+ &codec_param);
+ pj_assert(status == PJ_SUCCESS);
+
+ /* Alloc encoder */
+ status = pjmedia_vid_codec_mgr_alloc_codec(NULL, codec_info, &codec);
+ if (status != PJ_SUCCESS) {
+ PJ_PERROR(3,(THIS_FILE, status, "Error allocating codec"));
+ goto on_exit;
+ }
+
+ codec_param.dir = PJMEDIA_DIR_ENCODING_DECODING;
+ codec_param.packing = PJMEDIA_VID_PACKING_PACKETS;
+ codec_param.enc_mtu = MTU;
+ codec_param.enc_fmt.det.vid.size.w = WIDTH;
+ codec_param.enc_fmt.det.vid.size.h = HEIGHT;
+ codec_param.enc_fmt.det.vid.fps.num = FPS;
+ codec_param.enc_fmt.det.vid.avg_bps = WIDTH * HEIGHT * FPS;
+
+ status = pjmedia_vid_codec_init(codec, pool);
+ if (status != PJ_SUCCESS) {
+ PJ_PERROR(3,(THIS_FILE, status, "Error initializing codec"));
+ goto on_exit;
+ }
+
+ status = pjmedia_vid_codec_open(codec, &codec_param);
+ if (status != PJ_SUCCESS) {
+ PJ_PERROR(3,(THIS_FILE, status, "Error opening codec"));
+ goto on_exit;
+ }
+
+ while (fread(yuv_frame, 1, YUV_SIZE, fyuv) == YUV_SIZE) {
+ pjmedia_frame frm_yuv, frm_enc[MAX_FRAMES];
+ pj_bool_t has_more = PJ_FALSE;
+ const pj_uint8_t start_nal[] = { 0, 0, 1 };
+ unsigned i;
+
+ ++ read_cnt;
+
+ pj_bzero(&frm_enc, sizeof(frm_enc));
+ pj_bzero(&frm_yuv, sizeof(frm_yuv));
+
+ frm_yuv.buf = yuv_frame;
+ frm_yuv.size = YUV_SIZE;
+
+ enc_cnt = 0;
+ frm_enc[enc_cnt].buf = enc_buf[enc_cnt];
+ frm_enc[enc_cnt].size = MTU;
+
+ status = pjmedia_vid_codec_encode_begin(codec, NULL, &frm_yuv,
+ MTU, &frm_enc[enc_cnt],
+ &has_more);
+ if (status != PJ_SUCCESS) {
+ PJ_PERROR(3,(THIS_FILE, status, "Codec encode error"));
+ goto on_exit;
+ }
+ if (frm_enc[enc_cnt].size) {
+ if (f264) {
+ fwrite(start_nal, 1, sizeof(start_nal), f264);
+ fwrite(frm_enc[enc_cnt].buf, 1, frm_enc[enc_cnt].size, f264);
+ }
+ ++pkt_cnt;
+ ++enc_cnt;
+ }
+
+ while (has_more) {
+
+ if (enc_cnt >= MAX_FRAMES) {
+ status = -1;
+ puts("Error: too many encoded frames");
+ goto on_exit;
+ }
+
+ has_more = PJ_FALSE;
+ frm_enc[enc_cnt].buf = enc_buf[enc_cnt];
+ frm_enc[enc_cnt].size = MTU;
+
+ status = pjmedia_vid_codec_encode_more(codec, MTU,
+ &frm_enc[enc_cnt],
+ &has_more);
+ if (status != PJ_SUCCESS) {
+ PJ_PERROR(3,(THIS_FILE, status, "Codec encode error"));
+ goto on_exit;
+ }
+
+ if (frm_enc[enc_cnt].size) {
+ if (f264) {
+ fwrite(start_nal, 1, sizeof(start_nal), f264);
+ fwrite(frm_enc[enc_cnt].buf, 1, frm_enc[enc_cnt].size,
+ f264);
+ }
+ ++pkt_cnt;
+ ++enc_cnt;
+ }
+ }
+
+ if (enc_cnt) {
+ frm_yuv.buf = yuv_frame;
+ frm_yuv.size = YUV_BUF_SIZE;
+ status = pjmedia_vid_codec_decode(codec, enc_cnt,
+ frm_enc,
+ YUV_BUF_SIZE,
+ &frm_yuv);
+ if (status != PJ_SUCCESS) {
+ PJ_PERROR(3,(THIS_FILE, status, "Codec decode error"));
+ goto on_exit;
+ }
+
+ if (frm_yuv.size != 0) {
+ ++dec_cnt;
+ }
+ }
+ }
+
+ printf("Done.\n"
+ " Read YUV frames: %d\n"
+ " Encoded packets: %d\n"
+ " Decoded YUV frames: %d\n",
+ read_cnt, pkt_cnt, dec_cnt);
+
+ /* Start deinitialization: */
+on_exit:
+ if (codec) {
+ pjmedia_vid_codec_close(codec);
+ pjmedia_vid_codec_mgr_dealloc_codec(NULL, codec);
+ }
+
+ if (f264)
+ fclose(f264);
+
+ if (fyuv)
+ fclose(fyuv);
+
+ /* Deinit codecs */
+ deinit_codecs();
+
+ /* Destroy event manager */
+ pjmedia_event_mgr_destroy(NULL);
+
+ /* Release application pool */
+ pj_pool_release( pool );
+
+ /* Destroy media endpoint. */
+ pjmedia_endpt_destroy( med_endpt );
+
+ /* Destroy pool factory */
+ pj_caching_pool_destroy( &cp );
+
+ /* Shutdown PJLIB */
+ pj_shutdown();
+
+ return (status == PJ_SUCCESS) ? 0 : 1;
+}
+
+
+#else
+
+int main(int argc, char *argv[])
+{
+ PJ_UNUSED_ARG(argc);
+ PJ_UNUSED_ARG(argv);
+ puts("Error: this sample requires video capability "
+ "(PJMEDIA_HAS_VIDEO == 1)");
+ return -1;
+}
+
+#endif /* PJMEDIA_HAS_VIDEO */
diff --git a/pjsip-apps/src/samples/vid_streamutil.c b/pjsip-apps/src/samples/vid_streamutil.c
index f9f0a0d7..44c4f899 100644
--- a/pjsip-apps/src/samples/vid_streamutil.c
+++ b/pjsip-apps/src/samples/vid_streamutil.c
@@ -121,6 +121,11 @@ static pj_status_t init_codecs(pj_pool_factory *pf)
/* To suppress warning about unused var when all codecs are disabled */
PJ_UNUSED_ARG(status);
+#if defined(PJMEDIA_HAS_OPENH264_CODEC) && PJMEDIA_HAS_OPENH264_CODEC != 0
+ status = pjmedia_codec_openh264_vid_init(NULL, pf);
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
+#endif
+
#if defined(PJMEDIA_HAS_FFMPEG_VID_CODEC) && PJMEDIA_HAS_FFMPEG_VID_CODEC != 0
status = pjmedia_codec_ffmpeg_vid_init(NULL, pf);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
@@ -137,6 +142,11 @@ static void deinit_codecs()
#if defined(PJMEDIA_HAS_FFMPEG_VID_CODEC) && PJMEDIA_HAS_FFMPEG_VID_CODEC != 0
pjmedia_codec_ffmpeg_vid_deinit();
#endif
+
+#if defined(PJMEDIA_HAS_OPENH264_CODEC) && PJMEDIA_HAS_OPENH264_CODEC != 0
+ pjmedia_codec_openh264_vid_deinit();
+#endif
+
}
static pj_status_t create_file_player( pj_pool_t *pool,
diff --git a/pjsip/src/pjsua-lib/pjsua_vid.c b/pjsip/src/pjsua-lib/pjsua_vid.c
index 026942d1..c12cfd16 100644
--- a/pjsip/src/pjsua-lib/pjsua_vid.c
+++ b/pjsip/src/pjsua-lib/pjsua_vid.c
@@ -73,6 +73,15 @@ pj_status_t pjsua_vid_subsys_init(void)
goto on_error;
}
+#if PJMEDIA_HAS_VIDEO && PJMEDIA_HAS_OPENH264_CODEC
+ status = pjmedia_codec_openh264_vid_init(NULL, &pjsua_var.cp.factory);
+ if (status != PJ_SUCCESS) {
+ PJ_PERROR(1,(THIS_FILE, status,
+ "Error initializing OpenH264 library"));
+ goto on_error;
+ }
+#endif
+
#if PJMEDIA_HAS_VIDEO && PJMEDIA_HAS_FFMPEG_VID_CODEC
status = pjmedia_codec_ffmpeg_vid_init(NULL, &pjsua_var.cp.factory);
if (status != PJ_SUCCESS) {
@@ -133,6 +142,10 @@ pj_status_t pjsua_vid_subsys_destroy(void)
pjmedia_codec_ffmpeg_vid_deinit();
#endif
+#if defined(PJMEDIA_HAS_OPENH264_CODEC) && PJMEDIA_HAS_OPENH264_CODEC != 0
+ pjmedia_codec_openh264_vid_deinit();
+#endif
+
if (pjmedia_vid_codec_mgr_instance())
pjmedia_vid_codec_mgr_destroy(NULL);