summaryrefslogtreecommitdiffstats
path: root/libavformat/tests
diff options
context:
space:
mode:
authorClément Bœsch <clement@stupeflix.com>2016-06-22 13:44:29 +0200
committerClément Bœsch <clement@stupeflix.com>2016-06-22 13:44:34 +0200
commit5d48e4eafa6c4559683892b8638d10508125f3cf (patch)
tree0d5becbd08d6ae319497dd32cbe9b67f4670cc5e /libavformat/tests
parent989a614b707dcff8abdffe28dc24ec64a83b2837 (diff)
parenta6a750c7ef240b72ce01e9653343a0ddf247d196 (diff)
downloadffmpeg-streaming-5d48e4eafa6c4559683892b8638d10508125f3cf.zip
ffmpeg-streaming-5d48e4eafa6c4559683892b8638d10508125f3cf.tar.gz
Merge commit 'a6a750c7ef240b72ce01e9653343a0ddf247d196'
* commit 'a6a750c7ef240b72ce01e9653343a0ddf247d196': tests: Move all test programs to a subdirectory Merged-by: Clément Bœsch <clement@stupeflix.com>
Diffstat (limited to 'libavformat/tests')
-rw-r--r--libavformat/tests/.gitignore6
-rw-r--r--libavformat/tests/movenc.c676
-rw-r--r--libavformat/tests/noproxy.c43
-rw-r--r--libavformat/tests/rtmpdh.c158
-rw-r--r--libavformat/tests/seek.c161
-rw-r--r--libavformat/tests/srtp.c167
-rw-r--r--libavformat/tests/url.c55
7 files changed, 1266 insertions, 0 deletions
diff --git a/libavformat/tests/.gitignore b/libavformat/tests/.gitignore
new file mode 100644
index 0000000..c8adb86
--- /dev/null
+++ b/libavformat/tests/.gitignore
@@ -0,0 +1,6 @@
+/movenc
+/noproxy
+/rtmpdh
+/seek
+/srtp
+/url
diff --git a/libavformat/tests/movenc.c b/libavformat/tests/movenc.c
new file mode 100644
index 0000000..786f1dc
--- /dev/null
+++ b/libavformat/tests/movenc.c
@@ -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;
+}
diff --git a/libavformat/tests/noproxy.c b/libavformat/tests/noproxy.c
new file mode 100644
index 0000000..782356c
--- /dev/null
+++ b/libavformat/tests/noproxy.c
@@ -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;
+}
diff --git a/libavformat/tests/rtmpdh.c b/libavformat/tests/rtmpdh.c
new file mode 100644
index 0000000..929b3f3
--- /dev/null
+++ b/libavformat/tests/rtmpdh.c
@@ -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;
+}
diff --git a/libavformat/tests/seek.c b/libavformat/tests/seek.c
new file mode 100644
index 0000000..7ed56ba
--- /dev/null
+++ b/libavformat/tests/seek.c
@@ -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;
+}
diff --git a/libavformat/tests/srtp.c b/libavformat/tests/srtp.c
new file mode 100644
index 0000000..89450ce
--- /dev/null
+++ b/libavformat/tests/srtp.c
@@ -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;
+}
diff --git a/libavformat/tests/url.c b/libavformat/tests/url.c
new file mode 100644
index 0000000..1623179
--- /dev/null
+++ b/libavformat/tests/url.c
@@ -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;
+}
OpenPOWER on IntegriCloud