Commit 5a59e477 authored by Stefan Westerfeld's avatar Stefan Westerfeld

Merge branch 'video-poc'

parents 82f184e4 c0f85f3b
Overview of Changes in audiowmark-0.4.0:
* add initial video watermarking support (videowmark)
Overview of Changes in audiowmark-0.3.0: Overview of Changes in audiowmark-0.3.0:
* replace padding at start with a partial B block * replace padding at start with a partial B block
......
...@@ -39,7 +39,6 @@ specified as hex-string): ...@@ -39,7 +39,6 @@ specified as hex-string):
Sample Rate: 48000 Sample Rate: 48000
Channels: 2 Channels: 2
Data Blocks: 4 Data Blocks: 4
Volume Norm: 0.987 (-0.12 dB)
.... ....
The most important options for adding a watermark are: The most important options for adding a watermark are:
...@@ -150,6 +149,48 @@ watermark. Fractional strengths (like 7.5) are possible. ...@@ -150,6 +149,48 @@ watermark. Fractional strengths (like 7.5) are possible.
audiowmark add --strength 15 in.wav out.wav 0123456789abcdef0011223344556677 audiowmark add --strength 15 in.wav out.wav 0123456789abcdef0011223344556677
audiowmark get --strength 15 out.wav audiowmark get --strength 15 out.wav
== Video Files
For video files, `videowmark` can be used to add a watermark to the audio track
of video files. To add a watermark, use
[subs=+quotes]
....
*$ videowmark add in.avi out.avi 0123456789abcdef0011223344556677*
Audio Codec: -c:a mp3 -ab 128000
Input: in.avi
Output: out.avi
Message: 0123456789abcdef0011223344556677
Strength: 10
Time: 3:53
Sample Rate: 44100
Channels: 2
Data Blocks: 4
....
To detect a watermark, use
[subs=+quotes]
....
*$ videowmark get out.avi*
pattern 0:05 0123456789abcdef0011223344556677 1.294 0.142 A
pattern 0:57 0123456789abcdef0011223344556677 1.191 0.144 B
pattern 0:57 0123456789abcdef0011223344556677 1.242 0.145 AB
pattern 1:49 0123456789abcdef0011223344556677 1.215 0.120 A
pattern 2:40 0123456789abcdef0011223344556677 1.079 0.128 B
pattern 2:40 0123456789abcdef0011223344556677 1.147 0.126 AB
pattern all 0123456789abcdef0011223344556677 1.195 0.104
....
The key and strength can be set using the command line options
--key <filename>::
Use watermarking key from file <filename> (see <<key>>).
--strength <s>::
Set the watermarking strength (see <<strength>>).
== Output as Stream == Output as Stream
Usually, an input file is read, watermarked and an output file is written. Usually, an input file is read, watermarked and an output file is written.
......
AC_INIT([audiowmark], [0.3.0]) AC_INIT([audiowmark], [0.4.0])
AC_CONFIG_SRCDIR([src/audiowmark.cc]) AC_CONFIG_SRCDIR([src/audiowmark.cc])
AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_MACRO_DIR([m4])
......
bin_PROGRAMS = audiowmark bin_PROGRAMS = audiowmark
dist_bin_SCRIPTS = videowmark
COMMON_SRC = utils.hh utils.cc convcode.hh convcode.cc random.hh random.cc wavdata.cc wavdata.hh \ COMMON_SRC = utils.hh utils.cc convcode.hh convcode.cc random.hh random.cc wavdata.cc wavdata.hh \
audiostream.cc audiostream.hh sfinputstream.cc sfinputstream.hh stdoutwavoutputstream.cc stdoutwavoutputstream.hh \ audiostream.cc audiostream.hh sfinputstream.cc sfinputstream.hh stdoutwavoutputstream.cc stdoutwavoutputstream.hh \
......
possible improvements: possible improvements:
- dynamic bit strength - dynamic bit strength
videowmark:
opus length ffprobe -show_format phil.mkv
...@@ -272,6 +272,14 @@ parse_options (int *argc_p, ...@@ -272,6 +272,14 @@ parse_options (int *argc_p,
Params::raw_input_format.set_sample_rate (r); Params::raw_input_format.set_sample_rate (r);
Params::raw_output_format.set_sample_rate (r); Params::raw_output_format.set_sample_rate (r);
} }
else if (check_arg (argc, argv, &i, "--set-input-label", &opt_arg))
{
Params::input_label = opt_arg;
}
else if (check_arg (argc, argv, &i, "--set-output-label", &opt_arg))
{
Params::output_label = opt_arg;
}
else if (check_arg (argc, argv, &i, "--quiet") else if (check_arg (argc, argv, &i, "--quiet")
|| check_arg (argc, argv, &i, "-q")) || check_arg (argc, argv, &i, "-q"))
{ {
......
#!/bin/bash
function die
{
echo >&2 "videowmark: error: $@"
exit 1
}
# auto detect codec and bitrate from input stream, generate ffmpeg options for audio encoder
function audio_encode_options
{
ffprobe -v error -print_format compact -show_streams "$1" | grep codec_type=audio | awk -F'|' '$1 == "stream" {
for (i = 0; i < NF; i++)
print $i
}' | awk -F= '
$1 == "codec_name" {
codec = $2;
# opus encoder is experimental, ffmpeg recommends libopus for encoding
if (codec == "opus")
codec = "libopus";
printf (" -c:a %s", codec);
}
$1 == "bit_rate" {
bit_rate = $2;
if (bit_rate != "N/A")
printf (" -ab %s", bit_rate);
}'
}
# count number of audio and video streams, typical output: "audio=1:video=1"
function audio_video_stream_count
{
ffprobe -v error -print_format compact -show_streams "$1" | awk -F'|' '
{
for (i = 1; i < NF; i++)
x[$i]++;
}
END {
printf "audio=%d:video=%d\n",x["codec_type=audio"],x["codec_type=video"]
}'
}
function create_temp_files
{
local fd
for fd in "$@"
do
local tmpfile=$(mktemp /tmp/videowmark.XXXXXX)
eval "exec $fd>$tmpfile"
rm "$tmpfile"
done
}
function extension
{
echo $1 | awk -F. '{ if (NF > 1) print $NF; }'
}
function add_watermark
{
local in_file="$1"
local out_file="$2"
local bits="$3"
# check file extensions
local ext_in=$(extension "$in_file")
local ext_out=$(extension "$out_file")
[ "$ext_in" == "$ext_out" ] || die "input/output extension must match ('$ext_in' vs. '$ext_out')"
# check audio/video stream count
local stream_count=$(audio_video_stream_count "$in_file")
[ "$stream_count" == "audio=1:video=1" ] || { \
echo >&2 "videowmark: detected input file stream count: $stream_count"
die "input file must have one audio stream and one video stream"
}
# create tmpfiles
create_temp_files 3 4
local orig_wav=/dev/fd/3
local wm_wav=/dev/fd/4
# get audio as wav
ffmpeg $FFMPEG_VERBOSE -y -i "$in_file" -f wav "$orig_wav" || die "extracting audio from video failed (ffmpeg)"
# watermark
[ -z "$QUIET" ] && echo >&2 "Audio Codec: $(audio_encode_options "$in_file")"
audiowmark "${AUDIOWMARK_ARGS[@]}" add "$orig_wav" "$wm_wav" "$bits" \
--set-input-label "$in_file" --set-output-label "$out_file" || die "watermark generation failed (audiowmark)"
# rejoin
ffmpeg $FFMPEG_VERBOSE -y -i "$in_file" -i "$wm_wav" -c:v copy $(audio_encode_options "$in_file") -map 0:v:0 -map 1:a:0 "$out_file" || \
die "merging video and watermarked audio failed (ffmpeg)"
}
function get_watermark
{
local in_file="$1"
# check audio/video stream count
local stream_count=$(audio_video_stream_count "$in_file")
[ "$stream_count" == "audio=1:video=1" ] || { \
echo >&2 "videowmark: detected input file stream count: $stream_count"
die "input file must have one audio stream and one video stream"
}
# create tmpfiles
create_temp_files 3
local wav=/dev/fd/3
# get audio as wav
ffmpeg $FFMPEG_VERBOSE -y -i "$in_file" -f wav "$wav" || die "extracting audio from video failed (ffmpeg)"
# get watermark
audiowmark "${AUDIOWMARK_ARGS[@]}" get "$wav" || die "retrieving watermark from audio failed (audiowmark)"
}
function show_help_and_exit
{
cat << EOH
usage: videowmark <command> [ <args>... ]
Commands:
* create a watermarked video file with a message
videowmark add <input_video> <watermarked_video> <message_hex>
* retrieve message
videowmark get <watermarked_video>
Global options:
--strength <s> set watermark strength
--key <file> load watermarking key from file
-q, --quiet disable information messages
-v, --verbose enable ffmpeg verbose output
EOH
exit 0
}
GETOPT_TEMP=`getopt -o vhq --long verbose,quiet,help,key:,strength: -n 'videowmark' -- "$@"`
[ $? != 0 ] && exit 1 # exit on option parser errors
eval set -- "$GETOPT_TEMP"
AUDIOWMARK_ARGS=()
FFMPEG_VERBOSE="-v error"
QUIET=""
export AV_LOG_FORCE_NOCOLOR=1 # disable colored messages from ffmpeg
while true; do
case "$1" in
-v | --verbose ) FFMPEG_VERBOSE="-v info"; shift ;;
-q | --quiet ) AUDIOWMARK_ARGS+=("-q"); QUIET=1; shift ;;
-h | --help ) show_help_and_exit ;;
--key ) AUDIOWMARK_ARGS+=("--key" "$2"); shift 2 ;;
--strength ) AUDIOWMARK_ARGS+=("--strength" "$2"); shift 2 ;;
-- ) shift; break ;;
* ) break ;;
esac
done
if [ "$1" == "add" ] && [ "$#" == 4 ]; then
add_watermark "$2" "$3" "$4"
elif [ "$1" == "get" ] && [ "$#" == 2 ]; then
get_watermark "$2"
elif [ "$1" == "probe" ] && [ "$#" == 2 ]; then
echo $2 $(audio_encode_options "$2")
else
echo "videowmark: error parsing command line arguments (use videowmark -h)"
fi
...@@ -582,10 +582,10 @@ add_watermark (const string& infile, const string& outfile, const string& bits) ...@@ -582,10 +582,10 @@ add_watermark (const string& infile, const string& outfile, const string& bits)
} }
/* write some informational messages */ /* write some informational messages */
info ("Input: %s\n", infile.c_str()); info ("Input: %s\n", Params::input_label.size() ? Params::input_label.c_str() : infile.c_str());
if (Params::input_format == Format::RAW) if (Params::input_format == Format::RAW)
info_format ("Raw Input", Params::raw_input_format); info_format ("Raw Input", Params::raw_input_format);
info ("Output: %s\n", outfile.c_str()); info ("Output: %s\n", Params::output_label.size() ? Params::output_label.c_str() : outfile.c_str());
if (Params::output_format == Format::RAW) if (Params::output_format == Format::RAW)
info_format ("Raw Output", Params::raw_output_format); info_format ("Raw Output", Params::raw_output_format);
info ("Message: %s\n", bit_vec_to_str (bitvec).c_str()); info ("Message: %s\n", bit_vec_to_str (bitvec).c_str());
......
...@@ -19,6 +19,9 @@ Format Params::output_format = Format::AUTO; ...@@ -19,6 +19,9 @@ Format Params::output_format = Format::AUTO;
RawFormat Params::raw_input_format; RawFormat Params::raw_input_format;
RawFormat Params::raw_output_format; RawFormat Params::raw_output_format;
std::string Params::input_label;
std::string Params::output_label;
using std::vector; using std::vector;
using std::complex; using std::complex;
......
...@@ -50,6 +50,10 @@ public: ...@@ -50,6 +50,10 @@ public:
static RawFormat raw_input_format; static RawFormat raw_input_format;
static RawFormat raw_output_format; static RawFormat raw_output_format;
// input/output labels can be set for pretty output for videowmark add
static std::string input_label;
static std::string output_label;
}; };
typedef std::array<int, 30> UpDownArray; typedef std::array<int, 30> UpDownArray;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment