Merge commit 'a6a750c7ef240b72ce01e9653343a0ddf247d196'

* commit 'a6a750c7ef240b72ce01e9653343a0ddf247d196':
  tests: Move all test programs to a subdirectory

Merged-by: Clément Bœsch <clement@stupeflix.com>
This commit is contained in:
Clément Bœsch
2016-06-22 13:44:29 +02:00
101 changed files with 364 additions and 285 deletions

6
libavformat/tests/.gitignore vendored Normal file
View File

@@ -0,0 +1,6 @@
/movenc
/noproxy
/rtmpdh
/seek
/srtp
/url

676
libavformat/tests/movenc.c Normal file
View File

@@ -0,0 +1,676 @@
/*
* Copyright (c) 2015 Martin Storsjo
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "config.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/mathematics.h"
#include "libavutil/md5.h"
#include "libavformat/avformat.h"
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#if !HAVE_GETOPT
#include "compat/getopt.c"
#endif
#define HASH_SIZE 16
static const uint8_t h264_extradata[] = {
0x01, 0x4d, 0x40, 0x1e, 0xff, 0xe1, 0x00, 0x02, 0x67, 0x4d, 0x01, 0x00, 0x02, 0x68, 0xef
};
static const uint8_t aac_extradata[] = {
0x12, 0x10
};
static const char *format = "mp4";
AVFormatContext *ctx;
uint8_t iobuf[32768];
AVDictionary *opts;
int write_file;
const char *cur_name;
FILE* out;
int out_size;
struct AVMD5* md5;
uint8_t hash[HASH_SIZE];
AVStream *video_st, *audio_st;
int64_t audio_dts, video_dts;
int bframes;
int64_t duration;
int64_t audio_duration;
int frames;
int gop_size;
int64_t next_p_pts;
enum AVPictureType last_picture;
int skip_write;
int skip_write_audio;
int clear_duration;
int num_warnings;
int check_faults;
static void count_warnings(void *avcl, int level, const char *fmt, va_list vl)
{
if (level == AV_LOG_WARNING)
num_warnings++;
}
static void init_count_warnings(void)
{
av_log_set_callback(count_warnings);
num_warnings = 0;
}
static void reset_count_warnings(void)
{
av_log_set_callback(av_log_default_callback);
}
static int io_write(void *opaque, uint8_t *buf, int size)
{
out_size += size;
av_md5_update(md5, buf, size);
if (out)
fwrite(buf, 1, size, out);
return size;
}
static void init_out(const char *name)
{
char buf[100];
cur_name = name;
snprintf(buf, sizeof(buf), "%s.%s", cur_name, format);
av_md5_init(md5);
if (write_file) {
out = fopen(buf, "wb");
if (!out)
perror(buf);
}
out_size = 0;
}
static void close_out(void)
{
int i;
av_md5_final(md5, hash);
for (i = 0; i < HASH_SIZE; i++)
printf("%02x", hash[i]);
printf(" %d %s\n", out_size, cur_name);
if (out)
fclose(out);
out = NULL;
}
static void check_func(int value, int line, const char *msg, ...)
{
if (!value) {
va_list ap;
va_start(ap, msg);
printf("%d: ", line);
vprintf(msg, ap);
printf("\n");
check_faults++;
va_end(ap);
}
}
#define check(value, ...) check_func(value, __LINE__, __VA_ARGS__)
static void init_fps(int bf, int audio_preroll, int fps)
{
AVStream *st;
ctx = avformat_alloc_context();
if (!ctx)
exit(1);
ctx->oformat = av_guess_format(format, NULL, NULL);
if (!ctx->oformat)
exit(1);
ctx->pb = avio_alloc_context(iobuf, sizeof(iobuf), AVIO_FLAG_WRITE, NULL, NULL, io_write, NULL);
if (!ctx->pb)
exit(1);
ctx->flags |= AVFMT_FLAG_BITEXACT;
st = avformat_new_stream(ctx, NULL);
if (!st)
exit(1);
st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
st->codecpar->codec_id = AV_CODEC_ID_H264;
st->codecpar->width = 640;
st->codecpar->height = 480;
st->time_base.num = 1;
st->time_base.den = 30;
st->codecpar->extradata_size = sizeof(h264_extradata);
st->codecpar->extradata = av_mallocz(st->codecpar->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
if (!st->codecpar->extradata)
exit(1);
memcpy(st->codecpar->extradata, h264_extradata, sizeof(h264_extradata));
video_st = st;
st = avformat_new_stream(ctx, NULL);
if (!st)
exit(1);
st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
st->codecpar->codec_id = AV_CODEC_ID_AAC;
st->codecpar->sample_rate = 44100;
st->codecpar->channels = 2;
st->time_base.num = 1;
st->time_base.den = 44100;
st->codecpar->extradata_size = sizeof(aac_extradata);
st->codecpar->extradata = av_mallocz(st->codecpar->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
if (!st->codecpar->extradata)
exit(1);
memcpy(st->codecpar->extradata, aac_extradata, sizeof(aac_extradata));
audio_st = st;
if (avformat_write_header(ctx, &opts) < 0)
exit(1);
av_dict_free(&opts);
frames = 0;
gop_size = 30;
duration = video_st->time_base.den / fps;
audio_duration = 1024LL * audio_st->time_base.den / audio_st->codecpar->sample_rate;
if (audio_preroll)
audio_preroll = 2048LL * audio_st->time_base.den / audio_st->codecpar->sample_rate;
bframes = bf;
video_dts = bframes ? -duration : 0;
audio_dts = -audio_preroll;
}
static void init(int bf, int audio_preroll)
{
init_fps(bf, audio_preroll, 30);
}
static void mux_frames(int n)
{
int end_frames = frames + n;
while (1) {
AVPacket pkt;
uint8_t pktdata[8] = { 0 };
av_init_packet(&pkt);
if (av_compare_ts(audio_dts, audio_st->time_base, video_dts, video_st->time_base) < 0) {
pkt.dts = pkt.pts = audio_dts;
pkt.stream_index = 1;
pkt.duration = audio_duration;
audio_dts += audio_duration;
} else {
if (frames == end_frames)
break;
pkt.dts = video_dts;
pkt.stream_index = 0;
pkt.duration = duration;
if ((frames % gop_size) == 0) {
pkt.flags |= AV_PKT_FLAG_KEY;
last_picture = AV_PICTURE_TYPE_I;
pkt.pts = pkt.dts + duration;
video_dts = pkt.pts;
} else {
if (last_picture == AV_PICTURE_TYPE_P) {
last_picture = AV_PICTURE_TYPE_B;
pkt.pts = pkt.dts;
video_dts = next_p_pts;
} else {
last_picture = AV_PICTURE_TYPE_P;
if (((frames + 1) % gop_size) == 0) {
pkt.pts = pkt.dts + duration;
video_dts = pkt.pts;
} else {
next_p_pts = pkt.pts = pkt.dts + 2 * duration;
video_dts += duration;
}
}
}
if (!bframes)
pkt.pts = pkt.dts;
frames++;
}
if (clear_duration)
pkt.duration = 0;
AV_WB32(pktdata + 4, pkt.pts);
pkt.data = pktdata;
pkt.size = 8;
if (skip_write)
continue;
if (skip_write_audio && pkt.stream_index == 1)
continue;
av_write_frame(ctx, &pkt);
}
}
static void mux_gops(int n)
{
mux_frames(gop_size * n);
}
static void skip_gops(int n)
{
skip_write = 1;
mux_gops(n);
skip_write = 0;
}
static void signal_init_ts(void)
{
AVPacket pkt;
av_init_packet(&pkt);
pkt.size = 0;
pkt.data = NULL;
pkt.stream_index = 0;
pkt.dts = video_dts;
pkt.pts = 0;
av_write_frame(ctx, &pkt);
pkt.stream_index = 1;
pkt.dts = pkt.pts = audio_dts;
av_write_frame(ctx, &pkt);
}
static void finish(void)
{
av_write_trailer(ctx);
av_free(ctx->pb);
avformat_free_context(ctx);
ctx = NULL;
}
static void help(void)
{
printf("movenc-test [-w]\n"
"-w write output into files\n");
}
int main(int argc, char **argv)
{
int c;
uint8_t header[HASH_SIZE];
uint8_t content[HASH_SIZE];
int empty_moov_pos;
int prev_pos;
for (;;) {
c = getopt(argc, argv, "wh");
if (c == -1)
break;
switch (c) {
case 'w':
write_file = 1;
break;
default:
case 'h':
help();
return 0;
}
}
av_register_all();
md5 = av_md5_alloc();
if (!md5)
return 1;
// Write a fragmented file with an initial moov that actually contains some
// samples. One moov+mdat with 1 second of data and one moof+mdat with 1
// second of data.
init_out("non-empty-moov");
av_dict_set(&opts, "movflags", "frag_keyframe", 0);
init(0, 0);
mux_gops(2);
finish();
close_out();
// Write a similar file, but with B-frames and audio preroll, handled
// via an edit list.
init_out("non-empty-moov-elst");
av_dict_set(&opts, "movflags", "frag_keyframe", 0);
av_dict_set(&opts, "use_editlist", "1", 0);
init(1, 1);
mux_gops(2);
finish();
close_out();
// Use B-frames but no audio-preroll, but without an edit list.
// Due to avoid_negative_ts == AVFMT_AVOID_NEG_TS_MAKE_ZERO, the dts
// of the first audio packet is > 0, but it is set to zero since edit
// lists aren't used, increasing the duration of the first packet instead.
init_out("non-empty-moov-no-elst");
av_dict_set(&opts, "movflags", "frag_keyframe", 0);
av_dict_set(&opts, "use_editlist", "0", 0);
init(1, 0);
mux_gops(2);
finish();
close_out();
format = "ismv";
// Write an ISMV, with B-frames and audio preroll.
init_out("ismv");
av_dict_set(&opts, "movflags", "frag_keyframe", 0);
init(1, 1);
mux_gops(2);
finish();
close_out();
format = "mp4";
// An initial moov that doesn't contain any samples, followed by two
// moof+mdat pairs.
init_out("empty-moov");
av_dict_set(&opts, "movflags", "frag_keyframe+empty_moov", 0);
av_dict_set(&opts, "use_editlist", "0", 0);
init(0, 0);
mux_gops(2);
finish();
close_out();
memcpy(content, hash, HASH_SIZE);
// Similar to the previous one, but with input that doesn't start at
// pts/dts 0. avoid_negative_ts behaves in the same way as
// in non-empty-moov-no-elst above.
init_out("empty-moov-no-elst");
av_dict_set(&opts, "movflags", "frag_keyframe+empty_moov", 0);
init(1, 0);
mux_gops(2);
finish();
close_out();
// Same as the previous one, but disable avoid_negative_ts (which
// would require using an edit list, but with empty_moov, one can't
// write a sensible edit list, when the start timestamps aren't known).
// This should trigger a warning - we check that the warning is produced.
init_count_warnings();
init_out("empty-moov-no-elst-no-adjust");
av_dict_set(&opts, "movflags", "frag_keyframe+empty_moov", 0);
av_dict_set(&opts, "avoid_negative_ts", "0", 0);
init(1, 0);
mux_gops(2);
finish();
close_out();
reset_count_warnings();
check(num_warnings > 0, "No warnings printed for unhandled start offset");
// Verify that delay_moov produces the same as empty_moov for
// simple input
init_out("delay-moov");
av_dict_set(&opts, "movflags", "frag_keyframe+delay_moov", 0);
av_dict_set(&opts, "use_editlist", "0", 0);
init(0, 0);
mux_gops(2);
finish();
close_out();
check(!memcmp(hash, content, HASH_SIZE), "delay_moov differs from empty_moov");
// Test writing content that requires an edit list using delay_moov
init_out("delay-moov-elst");
av_dict_set(&opts, "movflags", "frag_keyframe+delay_moov", 0);
init(1, 1);
mux_gops(2);
finish();
close_out();
// Test writing a file with one track lacking packets, with delay_moov.
skip_write_audio = 1;
init_out("delay-moov-empty-track");
av_dict_set(&opts, "movflags", "frag_keyframe+delay_moov", 0);
init(0, 0);
mux_gops(2);
// The automatic flushing shouldn't output anything, since we're still
// waiting for data for some tracks
check(out_size == 0, "delay_moov flushed prematurely");
// When closed (or manually flushed), all the written data should still
// be output.
finish();
close_out();
check(out_size > 0, "delay_moov didn't output anything");
// Check that manually flushing still outputs things as expected. This
// produces two fragments, while the one above produces only one.
init_out("delay-moov-empty-track-flush");
av_dict_set(&opts, "movflags", "frag_custom+delay_moov", 0);
init(0, 0);
mux_gops(1);
av_write_frame(ctx, NULL); // Force writing the moov
check(out_size > 0, "No moov written");
av_write_frame(ctx, NULL);
mux_gops(1);
av_write_frame(ctx, NULL);
finish();
close_out();
skip_write_audio = 0;
// Verify that the header written by delay_moov when manually flushed
// is identical to the one by empty_moov.
init_out("empty-moov-header");
av_dict_set(&opts, "movflags", "frag_keyframe+empty_moov", 0);
av_dict_set(&opts, "use_editlist", "0", 0);
init(0, 0);
close_out();
memcpy(header, hash, HASH_SIZE);
init_out("empty-moov-content");
mux_gops(2);
// Written 2 seconds of content, with an automatic flush after 1 second.
check(out_size > 0, "No automatic flush?");
empty_moov_pos = prev_pos = out_size;
// Manually flush the second fragment
av_write_frame(ctx, NULL);
check(out_size > prev_pos, "No second fragment flushed?");
prev_pos = out_size;
// Check that an extra flush doesn't output any more data
av_write_frame(ctx, NULL);
check(out_size == prev_pos, "More data written?");
close_out();
memcpy(content, hash, HASH_SIZE);
// Ignore the trailer written here
finish();
init_out("delay-moov-header");
av_dict_set(&opts, "movflags", "frag_custom+delay_moov", 0);
av_dict_set(&opts, "use_editlist", "0", 0);
init(0, 0);
check(out_size == 0, "Output written during init with delay_moov");
mux_gops(1); // Write 1 second of content
av_write_frame(ctx, NULL); // Force writing the moov
close_out();
check(!memcmp(hash, header, HASH_SIZE), "delay_moov header differs from empty_moov");
init_out("delay-moov-content");
av_write_frame(ctx, NULL); // Flush the first fragment
check(out_size == empty_moov_pos, "Manually flushed content differs from automatically flushed, %d vs %d", out_size, empty_moov_pos);
mux_gops(1); // Write the rest of the content
av_write_frame(ctx, NULL); // Flush the second fragment
close_out();
check(!memcmp(hash, content, HASH_SIZE), "delay_moov content differs from empty_moov");
finish();
// Verify that we can produce an identical second fragment without
// writing the first one. First write the reference fragments that
// we want to reproduce.
av_dict_set(&opts, "movflags", "frag_custom+empty_moov+dash", 0);
init(0, 0);
mux_gops(1);
av_write_frame(ctx, NULL); // Output the first fragment
init_out("empty-moov-second-frag");
mux_gops(1);
av_write_frame(ctx, NULL); // Output the second fragment
close_out();
memcpy(content, hash, HASH_SIZE);
finish();
// Produce the same second fragment without actually writing the first
// one before.
av_dict_set(&opts, "movflags", "frag_custom+empty_moov+dash+frag_discont", 0);
av_dict_set(&opts, "fragment_index", "2", 0);
av_dict_set(&opts, "avoid_negative_ts", "0", 0);
av_dict_set(&opts, "use_editlist", "0", 0);
init(0, 0);
skip_gops(1);
init_out("empty-moov-second-frag-discont");
mux_gops(1);
av_write_frame(ctx, NULL); // Output the second fragment
close_out();
check(!memcmp(hash, content, HASH_SIZE), "discontinuously written fragment differs");
finish();
// Produce the same thing by using delay_moov, which requires a slightly
// different call sequence.
av_dict_set(&opts, "movflags", "frag_custom+delay_moov+dash+frag_discont", 0);
av_dict_set(&opts, "fragment_index", "2", 0);
init(0, 0);
skip_gops(1);
mux_gops(1);
av_write_frame(ctx, NULL); // Output the moov
init_out("delay-moov-second-frag-discont");
av_write_frame(ctx, NULL); // Output the second fragment
close_out();
check(!memcmp(hash, content, HASH_SIZE), "discontinuously written fragment differs");
finish();
// Test discontinuously written fragments with B-frames (where the
// assumption of starting at pts=0 works) but not with audio preroll
// (which can't be guessed).
av_dict_set(&opts, "movflags", "frag_custom+delay_moov+dash", 0);
init(1, 0);
mux_gops(1);
init_out("delay-moov-elst-init");
av_write_frame(ctx, NULL); // Output the moov
close_out();
memcpy(header, hash, HASH_SIZE);
av_write_frame(ctx, NULL); // Output the first fragment
init_out("delay-moov-elst-second-frag");
mux_gops(1);
av_write_frame(ctx, NULL); // Output the second fragment
close_out();
memcpy(content, hash, HASH_SIZE);
finish();
av_dict_set(&opts, "movflags", "frag_custom+delay_moov+dash+frag_discont", 0);
av_dict_set(&opts, "fragment_index", "2", 0);
init(1, 0);
skip_gops(1);
mux_gops(1); // Write the second fragment
init_out("delay-moov-elst-init-discont");
av_write_frame(ctx, NULL); // Output the moov
close_out();
check(!memcmp(hash, header, HASH_SIZE), "discontinuously written header differs");
init_out("delay-moov-elst-second-frag-discont");
av_write_frame(ctx, NULL); // Output the second fragment
close_out();
check(!memcmp(hash, content, HASH_SIZE), "discontinuously written fragment differs");
finish();
// Test discontinuously written fragments with B-frames and audio preroll,
// properly signaled.
av_dict_set(&opts, "movflags", "frag_custom+delay_moov+dash", 0);
init(1, 1);
mux_gops(1);
init_out("delay-moov-elst-signal-init");
av_write_frame(ctx, NULL); // Output the moov
close_out();
memcpy(header, hash, HASH_SIZE);
av_write_frame(ctx, NULL); // Output the first fragment
init_out("delay-moov-elst-signal-second-frag");
mux_gops(1);
av_write_frame(ctx, NULL); // Output the second fragment
close_out();
memcpy(content, hash, HASH_SIZE);
finish();
av_dict_set(&opts, "movflags", "frag_custom+delay_moov+dash+frag_discont", 0);
av_dict_set(&opts, "fragment_index", "2", 0);
init(1, 1);
signal_init_ts();
skip_gops(1);
mux_gops(1); // Write the second fragment
init_out("delay-moov-elst-signal-init-discont");
av_write_frame(ctx, NULL); // Output the moov
close_out();
check(!memcmp(hash, header, HASH_SIZE), "discontinuously written header differs");
init_out("delay-moov-elst-signal-second-frag-discont");
av_write_frame(ctx, NULL); // Output the second fragment
close_out();
check(!memcmp(hash, content, HASH_SIZE), "discontinuously written fragment differs");
finish();
// Test VFR content, with sidx atoms (which declare the pts duration
// of a fragment, forcing overriding the start pts of the next one).
// Here, the fragment duration in pts is significantly different from
// the duration in dts. The video stream starts at dts=-10,pts=0, and
// the second fragment starts at dts=155,pts=156. The trun duration sum
// of the first fragment is 165, which also is written as
// baseMediaDecodeTime in the tfdt in the second fragment. The sidx for
// the first fragment says earliest_presentation_time = 0 and
// subsegment_duration = 156, which also matches the sidx in the second
// fragment. For the audio stream, the pts and dts durations also don't
// match - the input stream starts at pts=-2048, but that part is excluded
// by the edit list.
init_out("vfr");
av_dict_set(&opts, "movflags", "frag_keyframe+delay_moov+dash", 0);
init_fps(1, 1, 3);
mux_frames(gop_size/2);
duration /= 10;
mux_frames(gop_size/2);
mux_gops(1);
finish();
close_out();
// Test VFR content, with cleared duration fields. In these cases,
// the muxer must guess the duration of the last packet of each
// fragment. As long as the framerate doesn't vary (too much) at the
// fragment edge, it works just fine. Additionally, when automatically
// cutting fragments, the muxer already know the timestamps of the next
// packet for one stream (in most cases the video stream), avoiding
// having to use guesses for that one.
init_count_warnings();
clear_duration = 1;
init_out("vfr-noduration");
av_dict_set(&opts, "movflags", "frag_keyframe+delay_moov+dash", 0);
init_fps(1, 1, 3);
mux_frames(gop_size/2);
duration /= 10;
mux_frames(gop_size/2);
mux_gops(1);
finish();
close_out();
clear_duration = 0;
reset_count_warnings();
check(num_warnings > 0, "No warnings printed for filled in durations");
av_free(md5);
return check_faults > 0 ? 1 : 0;
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright (c) 2013 Martin Storsjo
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "libavformat/network.h"
static void test(const char *pattern, const char *host)
{
int res = ff_http_match_no_proxy(pattern, host);
printf("The pattern \"%s\" %s the hostname %s\n",
pattern ? pattern : "(null)", res ? "matches" : "does not match",
host);
}
int main(void)
{
test(NULL, "domain.com");
test("example.com domain.com", "domain.com");
test("example.com other.com", "domain.com");
test("example.com,domain.com", "domain.com");
test("example.com,domain.com", "otherdomain.com");
test("example.com, *.domain.com", "sub.domain.com");
test("example.com, *.domain.com", "domain.com");
test("example.com, .domain.com", "domain.com");
test("*", "domain.com");
return 0;
}

158
libavformat/tests/rtmpdh.c Normal file
View File

@@ -0,0 +1,158 @@
/*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "libavformat/rtmpdh.c"
#include <stdio.h>
static int test_random_shared_secret(void)
{
FF_DH *peer1 = NULL, *peer2 = NULL;
int ret;
uint8_t pubkey1[128], pubkey2[128];
uint8_t sharedkey1[128], sharedkey2[128];
peer1 = ff_dh_init(1024);
peer2 = ff_dh_init(1024);
if (!peer1 || !peer2) {
ret = AVERROR(ENOMEM);
goto fail;
}
if ((ret = ff_dh_generate_public_key(peer1)) < 0)
goto fail;
if ((ret = ff_dh_generate_public_key(peer2)) < 0)
goto fail;
if ((ret = ff_dh_write_public_key(peer1, pubkey1, sizeof(pubkey1))) < 0)
goto fail;
if ((ret = ff_dh_write_public_key(peer2, pubkey2, sizeof(pubkey2))) < 0)
goto fail;
if ((ret = ff_dh_compute_shared_secret_key(peer1, pubkey2, sizeof(pubkey2),
sharedkey1, sizeof(sharedkey1))) < 0)
goto fail;
if ((ret = ff_dh_compute_shared_secret_key(peer2, pubkey1, sizeof(pubkey1),
sharedkey2, sizeof(sharedkey2))) < 0)
goto fail;
if (memcmp(sharedkey1, sharedkey2, sizeof(sharedkey1))) {
printf("Mismatched generated shared key\n");
ret = AVERROR_INVALIDDATA;
} else {
printf("Generated shared key ok\n");
}
fail:
ff_dh_free(peer1);
ff_dh_free(peer2);
return ret;
}
static const char *private_key =
"976C18FCADC255B456564F74F3EEDA59D28AF6B744D743F2357BFD2404797EF896EF1A"
"7C1CBEAAA3AB60AF3192D189CFF3F991C9CBBFD78119FCA2181384B94011943B6D6F28"
"9E1B708E2D1A0C7771169293F03DA27E561F15F16F0AC9BC858C77A80FA98FD088A232"
"19D08BE6F165DE0B02034B18705829FAD0ACB26A5B75EF";
static const char *public_key =
"F272ECF8362257C5D2C3CC2229CF9C0A03225BC109B1DBC76A68C394F256ACA3EF5F64"
"FC270C26382BF315C19E97A76104A716FC998A651E8610A3AE6CF65D8FAE5D3F32EEA0"
"0B32CB9609B494116A825D7142D17B88E3D20EDD98743DE29CF37A23A9F6A58B960591"
"3157D5965FCB46DDA73A1F08DD897BAE88DFE6FC937CBA";
static const uint8_t public_key_bin[] = {
0xf2, 0x72, 0xec, 0xf8, 0x36, 0x22, 0x57, 0xc5, 0xd2, 0xc3, 0xcc, 0x22,
0x29, 0xcf, 0x9c, 0x0a, 0x03, 0x22, 0x5b, 0xc1, 0x09, 0xb1, 0xdb, 0xc7,
0x6a, 0x68, 0xc3, 0x94, 0xf2, 0x56, 0xac, 0xa3, 0xef, 0x5f, 0x64, 0xfc,
0x27, 0x0c, 0x26, 0x38, 0x2b, 0xf3, 0x15, 0xc1, 0x9e, 0x97, 0xa7, 0x61,
0x04, 0xa7, 0x16, 0xfc, 0x99, 0x8a, 0x65, 0x1e, 0x86, 0x10, 0xa3, 0xae,
0x6c, 0xf6, 0x5d, 0x8f, 0xae, 0x5d, 0x3f, 0x32, 0xee, 0xa0, 0x0b, 0x32,
0xcb, 0x96, 0x09, 0xb4, 0x94, 0x11, 0x6a, 0x82, 0x5d, 0x71, 0x42, 0xd1,
0x7b, 0x88, 0xe3, 0xd2, 0x0e, 0xdd, 0x98, 0x74, 0x3d, 0xe2, 0x9c, 0xf3,
0x7a, 0x23, 0xa9, 0xf6, 0xa5, 0x8b, 0x96, 0x05, 0x91, 0x31, 0x57, 0xd5,
0x96, 0x5f, 0xcb, 0x46, 0xdd, 0xa7, 0x3a, 0x1f, 0x08, 0xdd, 0x89, 0x7b,
0xae, 0x88, 0xdf, 0xe6, 0xfc, 0x93, 0x7c, 0xba
};
static const uint8_t peer_public_key[] = {
0x58, 0x66, 0x05, 0x49, 0x94, 0x23, 0x2b, 0x66, 0x52, 0x13, 0xff, 0x46,
0xf2, 0xb3, 0x79, 0xa9, 0xee, 0xae, 0x1a, 0x13, 0xf0, 0x71, 0x52, 0xfb,
0x93, 0x4e, 0xee, 0x97, 0x05, 0x73, 0x50, 0x7d, 0xaf, 0x02, 0x07, 0x72,
0xac, 0xdc, 0xa3, 0x95, 0x78, 0xee, 0x9a, 0x19, 0x71, 0x7e, 0x99, 0x9f,
0x2a, 0xd4, 0xb3, 0xe2, 0x0c, 0x1d, 0x1a, 0x78, 0x4c, 0xde, 0xf1, 0xad,
0xb4, 0x60, 0xa8, 0x51, 0xac, 0x71, 0xec, 0x86, 0x70, 0xa2, 0x63, 0x36,
0x92, 0x7c, 0xe3, 0x87, 0xee, 0xe4, 0xf1, 0x62, 0x24, 0x74, 0xb4, 0x04,
0xfa, 0x5c, 0xdf, 0xba, 0xfa, 0xa3, 0xc2, 0xbb, 0x62, 0x27, 0xd0, 0xf4,
0xe4, 0x43, 0xda, 0x8a, 0x88, 0x69, 0x60, 0xe2, 0xdb, 0x75, 0x2a, 0x98,
0x9d, 0xb5, 0x50, 0xe3, 0x99, 0xda, 0xe0, 0xa6, 0x14, 0xc9, 0x80, 0x12,
0xf9, 0x3c, 0xac, 0x06, 0x02, 0x7a, 0xde, 0x74
};
static const uint8_t shared_secret[] = {
0xb2, 0xeb, 0xcb, 0x71, 0xf3, 0x61, 0xfb, 0x5b, 0x4e, 0x5c, 0x4c, 0xcf,
0x5c, 0x08, 0x5f, 0x96, 0x26, 0x77, 0x1d, 0x31, 0xf1, 0xe1, 0xf7, 0x4b,
0x92, 0xac, 0x82, 0x2a, 0x88, 0xc7, 0x83, 0xe1, 0xc7, 0xf3, 0xd3, 0x1a,
0x7d, 0xc8, 0x31, 0xe3, 0x97, 0xe4, 0xec, 0x31, 0x0e, 0x8f, 0x73, 0x1a,
0xe4, 0xf6, 0xd8, 0xc8, 0x94, 0xff, 0xa0, 0x03, 0x84, 0x03, 0x0f, 0xa5,
0x30, 0x5d, 0x67, 0xe0, 0x7a, 0x3b, 0x5f, 0xed, 0x4c, 0xf5, 0xbc, 0x18,
0xea, 0xd4, 0x77, 0xa9, 0x07, 0xb3, 0x54, 0x0b, 0x02, 0xd9, 0xc6, 0xb8,
0x66, 0x5e, 0xec, 0xa4, 0xcd, 0x47, 0xed, 0xc9, 0x38, 0xc6, 0x91, 0x08,
0xf3, 0x85, 0x9b, 0x69, 0x16, 0x78, 0x0d, 0xb7, 0x74, 0x51, 0xaa, 0x5b,
0x4d, 0x74, 0xe4, 0x29, 0x2e, 0x9e, 0x8e, 0xf7, 0xe5, 0x42, 0x83, 0xb0,
0x65, 0xb0, 0xce, 0xc6, 0xb2, 0x8f, 0x5b, 0xb0
};
static int test_ref_data(void)
{
FF_DH *dh;
int ret = AVERROR(ENOMEM);
uint8_t pubkey_test[128];
uint8_t sharedkey_test[128];
dh = ff_dh_init(1024);
if (!dh)
goto fail;
bn_hex2bn(dh->priv_key, private_key, ret);
if (!ret)
goto fail;
bn_hex2bn(dh->pub_key, public_key, ret);
if (!ret)
goto fail;
if ((ret = ff_dh_write_public_key(dh, pubkey_test, sizeof(pubkey_test))) < 0)
goto fail;
if (memcmp(pubkey_test, public_key_bin, sizeof(pubkey_test))) {
printf("Mismatched generated public key\n");
ret = AVERROR_INVALIDDATA;
goto fail;
} else {
printf("Generated public key ok\n");
}
if ((ret = ff_dh_compute_shared_secret_key(dh, peer_public_key, sizeof(peer_public_key),
sharedkey_test, sizeof(sharedkey_test))) < 0)
goto fail;
if (memcmp(shared_secret, sharedkey_test, sizeof(sharedkey_test))) {
printf("Mismatched generated shared key\n");
ret = AVERROR_INVALIDDATA;
} else {
printf("Generated shared key ok\n");
}
fail:
ff_dh_free(dh);
return ret;
}
int main(void)
{
if (test_random_shared_secret() < 0)
return 1;
if (test_ref_data() < 0)
return 1;
return 0;
}

161
libavformat/tests/seek.c Normal file
View File

@@ -0,0 +1,161 @@
/*
* Copyright (c) 2003 Fabrice Bellard
* Copyright (c) 2007 Michael Niedermayer
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "libavutil/common.h"
#include "libavutil/mathematics.h"
#include "libavformat/avformat.h"
static char buffer[20];
static const char *ret_str(int v)
{
switch (v) {
case AVERROR_EOF: return "-EOF";
case AVERROR(EIO): return "-EIO";
case AVERROR(ENOMEM): return "-ENOMEM";
case AVERROR(EINVAL): return "-EINVAL";
default:
snprintf(buffer, sizeof(buffer), "%2d", v);
return buffer;
}
}
static void ts_str(char buffer[60], int64_t ts, AVRational base)
{
if (ts == AV_NOPTS_VALUE) {
strcpy(buffer, " NOPTS ");
return;
}
ts= av_rescale_q(ts, base, (AVRational){1, 1000000});
snprintf(buffer, 60, "%c%"PRId64".%06"PRId64"", ts<0 ? '-' : ' ', FFABS(ts)/1000000, FFABS(ts)%1000000);
}
int main(int argc, char **argv)
{
const char *filename;
AVFormatContext *ic = avformat_alloc_context();
int i, ret, stream_id;
int j;
int64_t timestamp;
AVDictionary *format_opts = NULL;
int64_t seekfirst = AV_NOPTS_VALUE;
int firstback=0;
int frame_count = 1;
int duration = 4;
for(i=2; i<argc; i+=2){
if (!strcmp(argv[i], "-seekforw")){
seekfirst = atoi(argv[i+1]);
} else if(!strcmp(argv[i], "-seekback")){
seekfirst = atoi(argv[i+1]);
firstback = 1;
} else if(!strcmp(argv[i], "-frames")){
frame_count = atoi(argv[i+1]);
} else if(!strcmp(argv[i], "-duration")){
duration = atoi(argv[i+1]);
} else if(!strcmp(argv[i], "-fastseek")) {
if (atoi(argv[i+1])) {
ic->flags |= AVFMT_FLAG_FAST_SEEK;
}
} else if(argv[i][0] == '-' && argv[i+1]) {
av_dict_set(&format_opts, argv[i] + 1, argv[i+1], 0);
} else {
argc = 1;
}
}
av_dict_set(&format_opts, "channels", "1", 0);
av_dict_set(&format_opts, "sample_rate", "22050", 0);
/* initialize libavcodec, and register all codecs and formats */
av_register_all();
if (argc < 2) {
printf("usage: %s input_file\n"
"\n", argv[0]);
return 1;
}
filename = argv[1];
ret = avformat_open_input(&ic, filename, NULL, &format_opts);
av_dict_free(&format_opts);
if (ret < 0) {
fprintf(stderr, "cannot open %s\n", filename);
return 1;
}
ret = avformat_find_stream_info(ic, NULL);
if (ret < 0) {
fprintf(stderr, "%s: could not find codec parameters\n", filename);
return 1;
}
if(seekfirst != AV_NOPTS_VALUE){
if(firstback) avformat_seek_file(ic, -1, INT64_MIN, seekfirst, seekfirst, 0);
else avformat_seek_file(ic, -1, seekfirst, seekfirst, INT64_MAX, 0);
}
for(i=0; ; i++){
AVPacket pkt = { 0 };
AVStream *av_uninit(st);
char ts_buf[60];
if(ret>=0){
for(j=0; j<frame_count; j++) {
ret= av_read_frame(ic, &pkt);
if(ret>=0){
char dts_buf[60];
st= ic->streams[pkt.stream_index];
ts_str(dts_buf, pkt.dts, st->time_base);
ts_str(ts_buf, pkt.pts, st->time_base);
printf("ret:%-10s st:%2d flags:%d dts:%s pts:%s pos:%7" PRId64 " size:%6d", ret_str(ret), pkt.stream_index, pkt.flags, dts_buf, ts_buf, pkt.pos, pkt.size);
av_packet_unref(&pkt);
} else
printf("ret:%s", ret_str(ret)); // necessary to avoid trailing whitespace
printf("\n");
}
}
if(i>25) break;
stream_id= (i>>1)%(ic->nb_streams+1) - 1;
timestamp= (i*19362894167LL) % (duration*AV_TIME_BASE) - AV_TIME_BASE;
if(stream_id>=0){
st= ic->streams[stream_id];
timestamp= av_rescale_q(timestamp, AV_TIME_BASE_Q, st->time_base);
}
//FIXME fully test the new seek API
if(i&1) ret = avformat_seek_file(ic, stream_id, INT64_MIN, timestamp, timestamp, 0);
else ret = avformat_seek_file(ic, stream_id, timestamp, timestamp, INT64_MAX, 0);
ts_str(ts_buf, timestamp, stream_id < 0 ? AV_TIME_BASE_Q : st->time_base);
printf("ret:%-10s st:%2d flags:%d ts:%s\n", ret_str(ret), stream_id, i&1, ts_buf);
}
avformat_close_input(&ic);
return 0;
}

167
libavformat/tests/srtp.c Normal file
View File

@@ -0,0 +1,167 @@
/*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "libavformat/rtpdec.h"
#include "libavformat/srtp.h"
static const char *aes128_80_key = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn";
static const uint8_t rtp_aes128_80[] = {
// RTP header
0x80, 0xe0, 0x12, 0x34, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78,
// encrypted payload
0x62, 0x69, 0x76, 0xca, 0xc5,
// HMAC
0xa1, 0xac, 0x1b, 0xb4, 0xa0, 0x1c, 0xd5, 0x49, 0x28, 0x99,
};
static const uint8_t rtcp_aes128_80[] = {
// RTCP header
0x81, 0xc9, 0x00, 0x07, 0x12, 0x34, 0x56, 0x78,
// encrypted payload
0x8a, 0xac, 0xdc, 0xa5, 0x4c, 0xf6, 0x78, 0xa6, 0x62, 0x8f, 0x24, 0xda,
0x6c, 0x09, 0x3f, 0xa9, 0x28, 0x7a, 0xb5, 0x7f, 0x1f, 0x0f, 0xc9, 0x35,
// RTCP index
0x80, 0x00, 0x00, 0x03,
// HMAC
0xe9, 0x3b, 0xc0, 0x5c, 0x0c, 0x06, 0x9f, 0xab, 0xc0, 0xde,
};
static const char *aes128_32_key = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn";
static const uint8_t rtp_aes128_32[] = {
// RTP header
0x80, 0xe0, 0x12, 0x34, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78,
// encrypted payload
0x62, 0x69, 0x76, 0xca, 0xc5,
// HMAC
0xa1, 0xac, 0x1b, 0xb4,
};
static const uint8_t rtcp_aes128_32[] = {
// RTCP header
0x81, 0xc9, 0x00, 0x07, 0x12, 0x34, 0x56, 0x78,
// encrypted payload
0x35, 0xe9, 0xb5, 0xff, 0x0d, 0xd1, 0xde, 0x70, 0x74, 0x10, 0xaa, 0x1b,
0xb2, 0x8d, 0xf0, 0x20, 0x02, 0x99, 0x6b, 0x1b, 0x0b, 0xd0, 0x47, 0x34,
// RTCP index
0x80, 0x00, 0x00, 0x04,
// HMAC
0x5b, 0xd2, 0xa9, 0x9d,
};
static const char *aes128_80_32_key = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn";
static const uint8_t rtp_aes128_80_32[] = {
// RTP header
0x80, 0xe0, 0x12, 0x34, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78,
// encrypted payload
0x62, 0x69, 0x76, 0xca, 0xc5,
// HMAC
0xa1, 0xac, 0x1b, 0xb4,
};
static const uint8_t rtcp_aes128_80_32[] = {
// RTCP header
0x81, 0xc9, 0x00, 0x07, 0x12, 0x34, 0x56, 0x78,
// encrypted payload
0xd6, 0xae, 0xc1, 0x58, 0x63, 0x70, 0xc9, 0x88, 0x66, 0x26, 0x1c, 0x53,
0xff, 0x5d, 0x5d, 0x2b, 0x0f, 0x8c, 0x72, 0x3e, 0xc9, 0x1d, 0x43, 0xf9,
// RTCP index
0x80, 0x00, 0x00, 0x05,
// HMAC
0x09, 0x16, 0xb4, 0x27, 0x9a, 0xe9, 0x92, 0x26, 0x4e, 0x10,
};
static void print_data(const uint8_t *buf, int len)
{
int i;
for (i = 0; i < len; i++)
printf("%02x", buf[i]);
printf("\n");
}
static int test_decrypt(struct SRTPContext *srtp, const uint8_t *in, int len,
uint8_t *out)
{
memcpy(out, in, len);
if (!ff_srtp_decrypt(srtp, out, &len)) {
print_data(out, len);
return len;
} else
return -1;
}
static void test_encrypt(const uint8_t *data, int in_len, const char *suite,
const char *key)
{
struct SRTPContext enc = { 0 }, dec = { 0 };
int len;
char buf[RTP_MAX_PACKET_LENGTH];
ff_srtp_set_crypto(&enc, suite, key);
ff_srtp_set_crypto(&dec, suite, key);
len = ff_srtp_encrypt(&enc, data, in_len, buf, sizeof(buf));
if (!ff_srtp_decrypt(&dec, buf, &len)) {
if (len == in_len && !memcmp(buf, data, len))
printf("Decrypted content matches input\n");
else
printf("Decrypted content doesn't match input\n");
} else {
printf("Decryption failed\n");
}
ff_srtp_free(&enc);
ff_srtp_free(&dec);
}
int main(void)
{
static const char *aes128_80_suite = "AES_CM_128_HMAC_SHA1_80";
static const char *aes128_32_suite = "AES_CM_128_HMAC_SHA1_32";
static const char *aes128_80_32_suite = "SRTP_AES128_CM_HMAC_SHA1_32";
static const char *test_key = "abcdefghijklmnopqrstuvwxyz1234567890ABCD";
uint8_t buf[RTP_MAX_PACKET_LENGTH];
struct SRTPContext srtp = { 0 };
int len;
ff_srtp_set_crypto(&srtp, aes128_80_suite, aes128_80_key);
len = test_decrypt(&srtp, rtp_aes128_80, sizeof(rtp_aes128_80), buf);
test_encrypt(buf, len, aes128_80_suite, test_key);
test_encrypt(buf, len, aes128_32_suite, test_key);
test_encrypt(buf, len, aes128_80_32_suite, test_key);
test_decrypt(&srtp, rtcp_aes128_80, sizeof(rtcp_aes128_80), buf);
test_encrypt(buf, len, aes128_80_suite, test_key);
test_encrypt(buf, len, aes128_32_suite, test_key);
test_encrypt(buf, len, aes128_80_32_suite, test_key);
ff_srtp_free(&srtp);
memset(&srtp, 0, sizeof(srtp)); // Clear the context
ff_srtp_set_crypto(&srtp, aes128_32_suite, aes128_32_key);
test_decrypt(&srtp, rtp_aes128_32, sizeof(rtp_aes128_32), buf);
test_decrypt(&srtp, rtcp_aes128_32, sizeof(rtcp_aes128_32), buf);
ff_srtp_free(&srtp);
memset(&srtp, 0, sizeof(srtp)); // Clear the context
ff_srtp_set_crypto(&srtp, aes128_80_32_suite, aes128_80_32_key);
test_decrypt(&srtp, rtp_aes128_80_32, sizeof(rtp_aes128_80_32), buf);
test_decrypt(&srtp, rtcp_aes128_80_32, sizeof(rtcp_aes128_80_32), buf);
ff_srtp_free(&srtp);
return 0;
}

55
libavformat/tests/url.c Normal file
View File

@@ -0,0 +1,55 @@
/*
* Copyright (c) 2012 Martin Storsjo
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "libavformat/url.h"
static void test(const char *base, const char *rel)
{
char buf[200], buf2[200];
ff_make_absolute_url(buf, sizeof(buf), base, rel);
printf("%s\n", buf);
if (base) {
/* Test in-buffer replacement */
snprintf(buf2, sizeof(buf2), "%s", base);
ff_make_absolute_url(buf2, sizeof(buf2), buf2, rel);
if (strcmp(buf, buf2)) {
printf("In-place handling of %s + %s failed\n", base, rel);
exit(1);
}
}
}
int main(void)
{
test(NULL, "baz");
test("/foo/bar", "baz");
test("/foo/bar", "../baz");
test("/foo/bar", "/baz");
test("http://server/foo/", "baz");
test("http://server/foo/bar", "baz");
test("http://server/foo/", "../baz");
test("http://server/foo/bar/123", "../../baz");
test("http://server/foo/bar/123", "/baz");
test("http://server/foo/bar/123", "https://other/url");
test("http://server/foo/bar?param=value/with/slashes", "/baz");
test("http://server/foo/bar?param&otherparam", "?someparam");
test("http://server/foo/bar", "//other/url");
return 0;
}