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:
* replace padding at start with a partial B block
......
......@@ -39,7 +39,6 @@ specified as hex-string):
Sample Rate: 48000
Channels: 2
Data Blocks: 4
Volume Norm: 0.987 (-0.12 dB)
....
The most important options for adding a watermark are:
......@@ -150,6 +149,48 @@ watermark. Fractional strengths (like 7.5) are possible.
audiowmark add --strength 15 in.wav out.wav 0123456789abcdef0011223344556677
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
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_AUX_DIR([build-aux])
AC_CONFIG_MACRO_DIR([m4])
......
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 \
audiostream.cc audiostream.hh sfinputstream.cc sfinputstream.hh stdoutwavoutputstream.cc stdoutwavoutputstream.hh \
......
possible improvements:
- dynamic bit strength
videowmark:
opus length ffprobe -show_format phil.mkv
......@@ -272,6 +272,14 @@ parse_options (int *argc_p,
Params::raw_input_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")
|| 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)
}
/* 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)
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)
info_format ("Raw Output", Params::raw_output_format);
info ("Message: %s\n", bit_vec_to_str (bitvec).c_str());
......
......@@ -19,6 +19,9 @@ Format Params::output_format = Format::AUTO;
RawFormat Params::raw_input_format;
RawFormat Params::raw_output_format;
std::string Params::input_label;
std::string Params::output_label;
using std::vector;
using std::complex;
......
......@@ -50,6 +50,10 @@ public:
static RawFormat raw_input_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;
......
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