blob: 88ca1e9c7e2710e3553786ee138fe0497aaf8c29 [file] [log] [blame]
Sergey Kandaurov706382e2014-03-26 19:58:00 +04001#!/usr/bin/perl
2
3# (C) Sergey Kandaurov
4# (C) Nginx, Inc.
5
6# Tests for mp4 module.
7# Ensures that requested stream duration is given with sane accuracy.
8
9###############################################################################
10
11use warnings;
12use strict;
13
14use Test::More;
15
16BEGIN { use FindBin; chdir($FindBin::Bin); }
17
18use lib 'lib';
Maxim Dounin758f4062020-11-17 17:39:09 +030019use Test::Nginx qw/ :DEFAULT http_content /;
Sergey Kandaurov706382e2014-03-26 19:58:00 +040020
21###############################################################################
22
23select STDERR; $| = 1;
24select STDOUT; $| = 1;
25
Sergey Kandaurov109fea72014-04-08 19:31:14 +040026my $t = Test::Nginx->new()->has(qw/http mp4/)->has_daemon('ffprobe')
27 ->has_daemon('ffmpeg')
Sergey Kandaurovd82add72014-04-11 17:24:34 +040028 ->write_file_expand('nginx.conf', <<'EOF');
Sergey Kandaurov706382e2014-03-26 19:58:00 +040029
30%%TEST_GLOBALS%%
31
32daemon off;
33
34events {
35}
36
37http {
38 %%TEST_GLOBALS_HTTP%%
39
40 server {
Andrey Zelenkove59bf362016-07-12 17:39:03 +030041 listen 127.0.0.1:8080;
Sergey Kandaurov706382e2014-03-26 19:58:00 +040042 server_name localhost;
43
44 location / {
45 mp4;
46 }
47 }
48}
49
50EOF
51
Sergey Kandaurovd82add72014-04-11 17:24:34 +040052plan(skip_all => 'no lavfi')
53 unless grep /lavfi/, `ffmpeg -loglevel quiet -formats`;
Sergey Kandaurovc7a05852018-01-11 19:23:45 +030054system('ffmpeg -nostdin -loglevel quiet -y '
Sergey Kandaurov706382e2014-03-26 19:58:00 +040055 . '-f lavfi -i testsrc=duration=10:size=320x200:rate=15 '
56 . '-f lavfi -i testsrc=duration=20:size=320x200:rate=15 '
57 . '-map 0:0 -map 1:0 -pix_fmt yuv420p -g 15 -c:v libx264 '
58 . "${\($t->testdir())}/test.mp4") == 0
59 or die "Can't create mp4 file: $!";
Sergey Kandaurovc7a05852018-01-11 19:23:45 +030060system('ffmpeg -nostdin -loglevel quiet -y '
Sergey Kandaurovbc6d9782016-09-19 19:09:45 +030061 . '-f lavfi -i testsrc=duration=10:size=320x200:rate=15 '
62 . '-f lavfi -i testsrc=duration=20:size=320x200:rate=15 '
63 . '-map 0:0 -map 1:0 -pix_fmt yuv420p -g 15 -c:v libx264 '
64 . '-movflags +faststart '
65 . "${\($t->testdir())}/no_mdat.mp4") == 0
66 or die "Can't create mp4 file: $!";
Sergey Kandaurov706382e2014-03-26 19:58:00 +040067
Sergey Kandaurovac4ecc82020-03-12 15:56:11 +030068my $sbad = <<'EOF';
6900000000: 00 00 00 1c 66 74 79 70 69 73 6f 6d 00 00 02 00 |....ftypisom....|
7000000010: 69 73 6f 6d 69 73 6f 32 6d 70 34 31 00 00 00 09 |isomiso2mp41....|
7100000020: 6d 64 61 74 00 00 00 00 94 6d 6f 6f 76 00 00 00 |mdat.....moov...|
7200000030: 8c 74 72 61 6b 00 00 00 84 6d 64 69 61 00 00 00 |.trak....mdia...|
7300000040: 7c 6d 69 6e 66 00 00 00 74 73 74 62 6c 00 00 00 ||minf...tstbl...|
7400000050: 18 73 74 74 73 00 00 00 00 00 00 00 01 00 00 03 |.stts...........|
7500000060: 3a 00 00 04 00 00 00 00 28 73 74 73 63 00 00 00 |:.......(stsc...|
7600000070: 00 00 00 00 02 00 00 00 01 00 00 03 0f 00 00 00 |................|
7700000080: 01 00 00 00 02 00 00 00 2b 00 00 00 01 00 00 00 |........+.......|
7800000090: 14 73 74 73 7a 00 00 00 00 00 00 05 a9 00 00 03 |.stsz...........|
79000000a0: 3b 00 00 00 18 63 6f 36 34 00 00 00 00 00 00 00 |;....co64.......|
80000000b0: 01 ff ff ff ff f0 0f fb e7 |.........|
81EOF
82
83$t->write_file('bad.mp4', unhex($sbad));
84$t->run()->plan(27);
Sergey Kandaurov706382e2014-03-26 19:58:00 +040085
86###############################################################################
87
Sergey Kandaurovbc6d9782016-09-19 19:09:45 +030088my $test_uri = '/test.mp4';
89
90again:
91
Sergey Kandaurov706382e2014-03-26 19:58:00 +040092is(durations($t, 0.0), '10.0 20.0', 'start zero');
93is(durations($t, 2), '8.0 18.0', 'start integer');
94is(durations($t, 7.1), '2.9 12.9', 'start float');
95
Sergey Kandaurov706382e2014-03-26 19:58:00 +040096is(durations($t, 6, 9), '3.0 3.0', 'start end integer');
97is(durations($t, 2.7, 5.6), '2.9 2.9', 'start end float');
98
99is(durations($t, undef, 9), '9.0 9.0', 'end integer');
100is(durations($t, undef, 5.6), '5.6 5.6', 'end float');
101
102# invalid range results in ignoring end argument
103
Sergey Kandaurovbc6d9782016-09-19 19:09:45 +0300104like(http_head("$test_uri?start=1&end=1"), qr/200 OK/, 'zero range');
105like(http_head("$test_uri?start=1&end=0"), qr/200 OK/, 'negative range');
Sergey Kandaurov706382e2014-03-26 19:58:00 +0400106
Sergey Kandaurovfeba3392014-04-07 20:25:39 +0400107# start/end values exceeding track/file duration
Sergey Kandaurov706382e2014-03-26 19:58:00 +0400108
Sergey Kandaurovbc6d9782016-09-19 19:09:45 +0300109unlike(http_head("$test_uri?end=11"), qr!HTTP/1.1 500!,
Sergey Kandaurovfeba3392014-04-07 20:25:39 +0400110 'end beyond short track');
Sergey Kandaurovbc6d9782016-09-19 19:09:45 +0300111unlike(http_head("$test_uri?end=21"), qr!HTTP/1.1 500!, 'end beyond EOF');
112unlike(http_head("$test_uri?start=11"), qr!HTTP/1.1 500!,
Sergey Kandaurov1466b932014-04-07 20:25:40 +0400113 'start beyond short track');
Sergey Kandaurovbc6d9782016-09-19 19:09:45 +0300114like(http_head("$test_uri?start=21"), qr!HTTP/1.1 500!, 'start beyond EOF');
115
116$test_uri = '/no_mdat.mp4', goto again unless $test_uri eq '/no_mdat.mp4';
Sergey Kandaurov706382e2014-03-26 19:58:00 +0400117
Sergey Kandaurovac4ecc82020-03-12 15:56:11 +0300118# corrupted formats
119
Sergey Kandaurovac4ecc82020-03-12 15:56:11 +0300120like(http_get("/bad.mp4?start=0.5"), qr/500 Internal/, 'co64 chunk beyond EOF');
121
Sergey Kandaurov706382e2014-03-26 19:58:00 +0400122###############################################################################
123
124sub durations {
125 my ($t, $start, $end) = @_;
126 my $path = $t->{_testdir} . '/frag.mp4';
127
Sergey Kandaurovbc6d9782016-09-19 19:09:45 +0300128 my $uri = $test_uri;
Sergey Kandaurov706382e2014-03-26 19:58:00 +0400129 if (defined $start) {
130 $uri .= "?start=$start";
131 if (defined $end) {
132 $uri .= "&end=$end";
133 }
134
135 } elsif (defined $end) {
136 $uri .= "?end=$end";
137 }
138
Maxim Dounin758f4062020-11-17 17:39:09 +0300139 $t->write_file('frag.mp4', http_content(http_get($uri)));
Sergey Kandaurov706382e2014-03-26 19:58:00 +0400140
141 my $r = `ffprobe -show_streams $path 2>/dev/null`;
142 Test::Nginx::log_core('||', $r);
143 sprintf "%.1f %.1f", $r =~ /duration=(\d+\.\d+)/g;
144}
145
Sergey Kandaurovac4ecc82020-03-12 15:56:11 +0300146sub unhex {
147 my ($input) = @_;
148 my $buffer = '';
149
150 for my $l ($input =~ m/: +((?:[0-9a-f]{2,4} +)+) /gms) {
151 for my $v ($l =~ m/[0-9a-f]{2}/g) {
152 $buffer .= chr(hex($v));
153 }
154 }
155
156 return $buffer;
157}
158
Sergey Kandaurov706382e2014-03-26 19:58:00 +0400159###############################################################################