mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2024-11-21 10:55:51 +02:00
Merge remote-tracking branch 'qatar/master'
* qatar/master: v410dec: Implement explode mode support zerocodec: fix direct rendering. wav: init st to NULL to avoid a false-positive warning. wavpack: set bits_per_raw_sample for S32 samples to properly identify 24-bit h264: refactor NAL decode loop RTMPTE protocol support RTMPE protocol support rtmp: Add ff_rtmp_calc_digest_pos() rtmp: Rename rtmp_calc_digest to ff_rtmp_calc_digest and make it global swscale: add missing HAVE_INLINE_ASM check. lavfi: place x86 inline assembly under HAVE_INLINE_ASM. vc1: Add a test for interlaced field pictures swscale: Mark all init functions as av_cold swscale: x86: Drop pointless _mmx suffix from filenames lavf: use conditional notation for default codec in muxer declarations. swscale: place inline assembly bilinear scaler under HAVE_INLINE_ASM. dsputil: ppc: cosmetics: pretty-print dsputil: x86: add SHUFFLE_MASK_W macro configure: respect CC_O setting in check_cc Conflicts: Changelog configure libavcodec/v410dec.c libavcodec/zerocodec.c libavformat/asfenc.c libavformat/version.h libswscale/utils.c libswscale/x86/swscale.c Merged-by: Michael Niedermayer <michaelni@gmx.at>
This commit is contained in:
commit
2cb4d51654
17
Changelog
17
Changelog
@ -21,21 +21,8 @@ version next:
|
||||
- Microsoft Expression Encoder Screen decoder
|
||||
- RTMPS protocol support
|
||||
- RTMPTS protocol support
|
||||
- showwaves filter
|
||||
- LucasArts SMUSH playback support
|
||||
- SAMI demuxer and decoder
|
||||
- RealText demuxer and decoder
|
||||
- Heart Of Darkness PAF playback support
|
||||
- iec61883 device
|
||||
- asettb filter
|
||||
- new option: -progress
|
||||
- 3GPP Timed Text decoder
|
||||
- GeoTIFF decoder support
|
||||
- ffmpeg -(no)stdin option
|
||||
- Opus decoder using libopus
|
||||
- caca output device using libcaca
|
||||
- alphaextract and alphamerge filters
|
||||
- concat filter
|
||||
- RTMPE protocol support
|
||||
- RTMPTE protocol support
|
||||
|
||||
|
||||
version 0.11:
|
||||
|
24
configure
vendored
24
configure
vendored
@ -667,11 +667,15 @@ check_cmd(){
|
||||
"$@" >> $logfile 2>&1
|
||||
}
|
||||
|
||||
cc_o(){
|
||||
eval printf '%s\\n' $CC_O
|
||||
}
|
||||
|
||||
check_cc(){
|
||||
log check_cc "$@"
|
||||
cat > $TMPC
|
||||
log_file $TMPC
|
||||
check_cmd $cc $CPPFLAGS $CFLAGS "$@" -c -o $TMPO $TMPC
|
||||
check_cmd $cc $CPPFLAGS $CFLAGS "$@" -c $(cc_o $TMPO) $TMPC
|
||||
}
|
||||
|
||||
check_cxx(){
|
||||
@ -1055,6 +1059,7 @@ CONFIG_LIST="
|
||||
fft
|
||||
fontconfig
|
||||
frei0r
|
||||
gcrypt
|
||||
gnutls
|
||||
gpl
|
||||
gray
|
||||
@ -1100,6 +1105,7 @@ CONFIG_LIST="
|
||||
memalign_hack
|
||||
memory_poisoning
|
||||
mpegaudiodsp
|
||||
nettle
|
||||
network
|
||||
nonfree
|
||||
openal
|
||||
@ -1731,6 +1737,9 @@ x11_grab_device_indev_deps="x11grab"
|
||||
|
||||
# protocols
|
||||
bluray_protocol_deps="libbluray"
|
||||
ffrtmpcrypt_protocol_deps="!librtmp_protocol"
|
||||
ffrtmpcrypt_protocol_deps_any="gcrypt nettle openssl"
|
||||
ffrtmpcrypt_protocol_select="tcp_protocol"
|
||||
ffrtmphttp_protocol_deps="!librtmp_protocol"
|
||||
ffrtmphttp_protocol_select="http_protocol"
|
||||
gopher_protocol_deps="network"
|
||||
@ -1748,9 +1757,11 @@ mmsh_protocol_select="http_protocol"
|
||||
mmst_protocol_deps="network"
|
||||
rtmp_protocol_deps="!librtmp_protocol"
|
||||
rtmp_protocol_select="tcp_protocol"
|
||||
rtmpe_protocol_select="ffrtmpcrypt_protocol"
|
||||
rtmps_protocol_deps="!librtmp_protocol"
|
||||
rtmps_protocol_select="tls_protocol"
|
||||
rtmpt_protocol_select="ffrtmphttp_protocol"
|
||||
rtmpte_protocol_select="ffrtmpcrypt_protocol ffrtmphttp_protocol"
|
||||
rtmpts_protocol_select="ffrtmphttp_protocol"
|
||||
rtp_protocol_select="udp_protocol"
|
||||
sctp_protocol_deps="network netinet_sctp_h"
|
||||
@ -2371,12 +2382,10 @@ elif $cc --vsn 2>/dev/null | grep -q "ARM C/C++ Compiler"; then
|
||||
elif $cc -version 2>/dev/null | grep -q TMS470; then
|
||||
cc_type=tms470
|
||||
cc_ident=$($cc -version | head -n1 | tr -s ' ')
|
||||
cc="$cc --gcc --abi=eabi -eo=.o -mc -me"
|
||||
CC_O='-fr=$(@D)'
|
||||
cc="$cc --gcc --abi=eabi -me"
|
||||
CC_O='-fe=$@'
|
||||
as_default="${cross_prefix}gcc"
|
||||
ld_default="${cross_prefix}gcc"
|
||||
TMPO=$(basename $TMPC .c).o
|
||||
append TMPFILES $TMPO
|
||||
add_cflags -D__gnuc_va_list=va_list -D__USER_LABEL_PREFIX__=
|
||||
CC_DEPFLAGS='-ppa -ppd=$(@:.o=.d)'
|
||||
AS_DEPFLAGS='-MMD'
|
||||
@ -3375,6 +3384,11 @@ enabled openssl && { check_lib openssl/ssl.h SSL_library_init -lssl -lcrypto
|
||||
check_lib openssl/ssl.h SSL_library_init -lssl -lcrypto -lws2_32 -lgdi32 ||
|
||||
die "ERROR: openssl not found"; }
|
||||
|
||||
if enabled gnutls; then
|
||||
{ check_lib nettle/bignum.h nettle_mpz_get_str_256 -lnettle -lhogweed -lgmp && enable nettle; } ||
|
||||
{ check_lib gcrypt.h gcry_mpi_new -lgcrypt && enable gcrypt; }
|
||||
fi
|
||||
|
||||
# libdc1394 check
|
||||
if enabled libdc1394; then
|
||||
{ check_lib dc1394/dc1394.h dc1394_new -ldc1394 -lraw1394 &&
|
||||
|
@ -904,10 +904,10 @@ performance on systems without hardware floating point support).
|
||||
@item MMST @tab X
|
||||
@item pipe @tab X
|
||||
@item RTMP @tab X
|
||||
@item RTMPE @tab E
|
||||
@item RTMPE @tab X
|
||||
@item RTMPS @tab X
|
||||
@item RTMPT @tab X
|
||||
@item RTMPTE @tab E
|
||||
@item RTMPTE @tab X
|
||||
@item RTMPTS @tab X
|
||||
@item RTP @tab X
|
||||
@item SCTP @tab X
|
||||
|
@ -277,6 +277,15 @@ For example to read with @command{ffplay} a multimedia resource named
|
||||
ffplay rtmp://myserver/vod/sample
|
||||
@end example
|
||||
|
||||
@section rtmpe
|
||||
|
||||
Encrypted Real-Time Messaging Protocol.
|
||||
|
||||
The Encrypted Real-Time Messaging Protocol (RTMPE) is used for
|
||||
streaming multimedia content within standard cryptographic primitives,
|
||||
consisting of Diffie-Hellman key exchange and HMACSHA256, generating
|
||||
a pair of RC4 keys.
|
||||
|
||||
@section rtmps
|
||||
|
||||
Real-Time Messaging Protocol over a secure SSL connection.
|
||||
@ -292,6 +301,14 @@ The Real-Time Messaging Protocol tunneled through HTTP (RTMPT) is used
|
||||
for streaming multimedia content within HTTP requests to traverse
|
||||
firewalls.
|
||||
|
||||
@section rtmpte
|
||||
|
||||
Encrypted Real-Time Messaging Protocol tunneled through HTTP.
|
||||
|
||||
The Encrypted Real-Time Messaging Protocol tunneled through HTTP (RTMPTE)
|
||||
is used for streaming multimedia content within HTTP requests to traverse
|
||||
firewalls.
|
||||
|
||||
@section rtmpts
|
||||
|
||||
Real-Time Messaging Protocol tunneled through HTTPS.
|
||||
|
@ -188,42 +188,50 @@ const uint8_t *ff_h264_decode_nal(H264Context *h, const uint8_t *src,
|
||||
src++;
|
||||
length--;
|
||||
|
||||
#define STARTCODE_TEST \
|
||||
if (i + 2 < length && src[i + 1] == 0 && src[i + 2] <= 3) { \
|
||||
if (src[i + 2] != 3) { \
|
||||
/* startcode, so we must be past the end */ \
|
||||
length = i; \
|
||||
} \
|
||||
break; \
|
||||
}
|
||||
#if HAVE_FAST_UNALIGNED
|
||||
#define FIND_FIRST_ZERO \
|
||||
if (i > 0 && !src[i]) \
|
||||
i--; \
|
||||
while (src[i]) \
|
||||
i++
|
||||
#if HAVE_FAST_64BIT
|
||||
#define RS 7
|
||||
for (i = 0; i + 1 < length; i += 9) {
|
||||
if (!((~AV_RN64A(src + i) &
|
||||
(AV_RN64A(src + i) - 0x0100010001000101ULL)) &
|
||||
0x8000800080008080ULL))
|
||||
continue;
|
||||
FIND_FIRST_ZERO;
|
||||
STARTCODE_TEST;
|
||||
i -= 7;
|
||||
}
|
||||
#else
|
||||
#define RS 3
|
||||
for (i = 0; i + 1 < length; i += 5) {
|
||||
if (!((~AV_RN32A(src + i) &
|
||||
(AV_RN32A(src + i) - 0x01000101U)) &
|
||||
0x80008080U))
|
||||
#endif
|
||||
continue;
|
||||
if (i > 0 && !src[i])
|
||||
i--;
|
||||
while (src[i])
|
||||
i++;
|
||||
FIND_FIRST_ZERO;
|
||||
STARTCODE_TEST;
|
||||
i -= 3;
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
#define RS 0
|
||||
for (i = 0; i + 1 < length; i += 2) {
|
||||
if (src[i])
|
||||
continue;
|
||||
if (i > 0 && src[i - 1] == 0)
|
||||
i--;
|
||||
#endif
|
||||
if (i + 2 < length && src[i + 1] == 0 && src[i + 2] <= 3) {
|
||||
if (src[i + 2] != 3) {
|
||||
/* startcode, so we must be past the end */
|
||||
length = i;
|
||||
}
|
||||
break;
|
||||
}
|
||||
i -= RS;
|
||||
STARTCODE_TEST;
|
||||
}
|
||||
#endif
|
||||
|
||||
// use second escape buffer for inter data
|
||||
bufidx = h->nal_unit_type == NAL_DPC ? 1 : 0;
|
||||
|
@ -23,7 +23,8 @@
|
||||
#include "libavutil/ppc/util_altivec.h"
|
||||
#include "dsputil_altivec.h"
|
||||
|
||||
static void int32_to_float_fmul_scalar_altivec(float *dst, const int *src, float mul, int len)
|
||||
static void int32_to_float_fmul_scalar_altivec(float *dst, const int *src,
|
||||
float mul, int len)
|
||||
{
|
||||
union {
|
||||
vector float v;
|
||||
@ -36,7 +37,7 @@ static void int32_to_float_fmul_scalar_altivec(float *dst, const int *src, float
|
||||
mul_u.s[0] = mul;
|
||||
mul_v = vec_splat(mul_u.v, 0);
|
||||
|
||||
for(i=0; i<len; i+=8) {
|
||||
for (i = 0; i < len; i += 8) {
|
||||
src1 = vec_ctf(vec_ld(0, src+i), 0);
|
||||
src2 = vec_ctf(vec_ld(16, src+i), 0);
|
||||
dst1 = vec_madd(src1, mul_v, zero);
|
||||
@ -47,8 +48,7 @@ static void int32_to_float_fmul_scalar_altivec(float *dst, const int *src, float
|
||||
}
|
||||
|
||||
|
||||
static vector signed short
|
||||
float_to_int16_one_altivec(const float *src)
|
||||
static vector signed short float_to_int16_one_altivec(const float *src)
|
||||
{
|
||||
vector float s0 = vec_ld(0, src);
|
||||
vector float s1 = vec_ld(16, src);
|
||||
@ -62,80 +62,82 @@ static void float_to_int16_altivec(int16_t *dst, const float *src, long len)
|
||||
int i;
|
||||
vector signed short d0, d1, d;
|
||||
vector unsigned char align;
|
||||
if(((long)dst)&15) //FIXME
|
||||
for(i=0; i<len-7; i+=8) {
|
||||
d0 = vec_ld(0, dst+i);
|
||||
d = float_to_int16_one_altivec(src+i);
|
||||
d1 = vec_ld(15, dst+i);
|
||||
d1 = vec_perm(d1, d0, vec_lvsl(0,dst+i));
|
||||
align = vec_lvsr(0, dst+i);
|
||||
d0 = vec_perm(d1, d, align);
|
||||
d1 = vec_perm(d, d1, align);
|
||||
vec_st(d0, 0, dst+i);
|
||||
vec_st(d1,15, dst+i);
|
||||
}
|
||||
else
|
||||
for(i=0; i<len-7; i+=8) {
|
||||
d = float_to_int16_one_altivec(src+i);
|
||||
vec_st(d, 0, dst+i);
|
||||
if (((long)dst) & 15) { //FIXME
|
||||
for (i = 0; i < len - 7; i += 8) {
|
||||
d0 = vec_ld(0, dst+i);
|
||||
d = float_to_int16_one_altivec(src + i);
|
||||
d1 = vec_ld(15, dst+i);
|
||||
d1 = vec_perm(d1, d0, vec_lvsl(0, dst + i));
|
||||
align = vec_lvsr(0, dst + i);
|
||||
d0 = vec_perm(d1, d, align);
|
||||
d1 = vec_perm(d, d1, align);
|
||||
vec_st(d0, 0, dst + i);
|
||||
vec_st(d1, 15, dst + i);
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < len - 7; i += 8) {
|
||||
d = float_to_int16_one_altivec(src + i);
|
||||
vec_st(d, 0, dst + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
float_to_int16_interleave_altivec(int16_t *dst, const float **src,
|
||||
long len, int channels)
|
||||
static void float_to_int16_interleave_altivec(int16_t *dst, const float **src,
|
||||
long len, int channels)
|
||||
{
|
||||
int i;
|
||||
vector signed short d0, d1, d2, c0, c1, t0, t1;
|
||||
vector unsigned char align;
|
||||
if(channels == 1)
|
||||
|
||||
if (channels == 1)
|
||||
float_to_int16_altivec(dst, src[0], len);
|
||||
else
|
||||
else {
|
||||
if (channels == 2) {
|
||||
if(((long)dst)&15)
|
||||
for(i=0; i<len-7; i+=8) {
|
||||
d0 = vec_ld(0, dst + i);
|
||||
t0 = float_to_int16_one_altivec(src[0] + i);
|
||||
d1 = vec_ld(31, dst + i);
|
||||
t1 = float_to_int16_one_altivec(src[1] + i);
|
||||
c0 = vec_mergeh(t0, t1);
|
||||
c1 = vec_mergel(t0, t1);
|
||||
d2 = vec_perm(d1, d0, vec_lvsl(0, dst + i));
|
||||
align = vec_lvsr(0, dst + i);
|
||||
d0 = vec_perm(d2, c0, align);
|
||||
d1 = vec_perm(c0, c1, align);
|
||||
vec_st(d0, 0, dst + i);
|
||||
d0 = vec_perm(c1, d2, align);
|
||||
vec_st(d1, 15, dst + i);
|
||||
vec_st(d0, 31, dst + i);
|
||||
dst+=8;
|
||||
}
|
||||
else
|
||||
for(i=0; i<len-7; i+=8) {
|
||||
t0 = float_to_int16_one_altivec(src[0] + i);
|
||||
t1 = float_to_int16_one_altivec(src[1] + i);
|
||||
d0 = vec_mergeh(t0, t1);
|
||||
d1 = vec_mergel(t0, t1);
|
||||
vec_st(d0, 0, dst + i);
|
||||
vec_st(d1, 16, dst + i);
|
||||
dst+=8;
|
||||
}
|
||||
} else {
|
||||
DECLARE_ALIGNED(16, int16_t, tmp)[len];
|
||||
int c, j;
|
||||
for (c = 0; c < channels; c++) {
|
||||
float_to_int16_altivec(tmp, src[c], len);
|
||||
for (i = 0, j = c; i < len; i++, j+=channels) {
|
||||
dst[j] = tmp[i];
|
||||
if (((long)dst) & 15) {
|
||||
for (i = 0; i < len - 7; i += 8) {
|
||||
d0 = vec_ld(0, dst + i);
|
||||
t0 = float_to_int16_one_altivec(src[0] + i);
|
||||
d1 = vec_ld(31, dst + i);
|
||||
t1 = float_to_int16_one_altivec(src[1] + i);
|
||||
c0 = vec_mergeh(t0, t1);
|
||||
c1 = vec_mergel(t0, t1);
|
||||
d2 = vec_perm(d1, d0, vec_lvsl(0, dst + i));
|
||||
align = vec_lvsr(0, dst + i);
|
||||
d0 = vec_perm(d2, c0, align);
|
||||
d1 = vec_perm(c0, c1, align);
|
||||
vec_st(d0, 0, dst + i);
|
||||
d0 = vec_perm(c1, d2, align);
|
||||
vec_st(d1, 15, dst + i);
|
||||
vec_st(d0, 31, dst + i);
|
||||
dst += 8;
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < len - 7; i += 8) {
|
||||
t0 = float_to_int16_one_altivec(src[0] + i);
|
||||
t1 = float_to_int16_one_altivec(src[1] + i);
|
||||
d0 = vec_mergeh(t0, t1);
|
||||
d1 = vec_mergel(t0, t1);
|
||||
vec_st(d0, 0, dst + i);
|
||||
vec_st(d1, 16, dst + i);
|
||||
dst += 8;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
DECLARE_ALIGNED(16, int16_t, tmp)[len];
|
||||
int c, j;
|
||||
for (c = 0; c < channels; c++) {
|
||||
float_to_int16_altivec(tmp, src[c], len);
|
||||
for (i = 0, j = c; i < len; i++, j+=channels)
|
||||
dst[j] = tmp[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ff_fmt_convert_init_altivec(FmtConvertContext *c, AVCodecContext *avctx)
|
||||
{
|
||||
c->int32_to_float_fmul_scalar = int32_to_float_fmul_scalar_altivec;
|
||||
if(!(avctx->flags & CODEC_FLAG_BITEXACT)) {
|
||||
if (!(avctx->flags & CODEC_FLAG_BITEXACT)) {
|
||||
c->float_to_int16 = float_to_int16_altivec;
|
||||
c->float_to_int16_interleave = float_to_int16_interleave_altivec;
|
||||
}
|
||||
|
@ -29,7 +29,12 @@ static av_cold int v410_decode_init(AVCodecContext *avctx)
|
||||
avctx->bits_per_raw_sample = 10;
|
||||
|
||||
if (avctx->width & 1) {
|
||||
av_log(avctx, AV_LOG_WARNING, "v410 requires width to be even.\n");
|
||||
if (avctx->err_recognition & AV_EF_EXPLODE) {
|
||||
av_log(avctx, AV_LOG_ERROR, "v410 requires width to be even, continuing anyway.\n");
|
||||
return AVERROR_INVALIDDATA;
|
||||
} else {
|
||||
av_log(avctx, AV_LOG_WARNING, "v410 requires width to be even.\n");
|
||||
}
|
||||
}
|
||||
|
||||
avctx->coded_frame = avcodec_alloc_frame();
|
||||
|
@ -28,7 +28,7 @@ pb_zzzzzzzz77777777: times 8 db -1
|
||||
pb_7: times 8 db 7
|
||||
pb_zzzz3333zzzzbbbb: db -1,-1,-1,-1,3,3,3,3,-1,-1,-1,-1,11,11,11,11
|
||||
pb_zz11zz55zz99zzdd: db -1,-1,1,1,-1,-1,5,5,-1,-1,9,9,-1,-1,13,13
|
||||
pb_revwords: db 14, 15, 12, 13, 10, 11, 8, 9, 6, 7, 4, 5, 2, 3, 0, 1
|
||||
pb_revwords: SHUFFLE_MASK_W 7, 6, 5, 4, 3, 2, 1, 0
|
||||
pd_16384: times 4 dd 16384
|
||||
pb_bswap32: db 3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12
|
||||
|
||||
|
@ -94,7 +94,7 @@ static int zerocodec_decode_frame(AVCodecContext *avctx, void *data,
|
||||
if (prev_pic->data[0])
|
||||
avctx->release_buffer(avctx, prev_pic);
|
||||
|
||||
*data_size = sizeof(AVFrame);
|
||||
*data_size = sizeof(AVFrame);
|
||||
*(AVFrame *)data = *pic;
|
||||
|
||||
/* Store the previous frame for use later.
|
||||
|
@ -23,6 +23,8 @@
|
||||
#include "libavutil/x86_cpu.h"
|
||||
#include "libavfilter/gradfun.h"
|
||||
|
||||
#if HAVE_INLINE_ASM
|
||||
|
||||
DECLARE_ALIGNED(16, static const uint16_t, pw_7f)[8] = {0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F};
|
||||
DECLARE_ALIGNED(16, static const uint16_t, pw_ff)[8] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
|
||||
|
||||
@ -164,10 +166,13 @@ static void gradfun_blur_line_sse2(uint16_t *dc, uint16_t *buf, const uint16_t *
|
||||
}
|
||||
#endif // HAVE_SSE
|
||||
|
||||
#endif /* HAVE_INLINE_ASM */
|
||||
|
||||
av_cold void ff_gradfun_init_x86(GradFunContext *gf)
|
||||
{
|
||||
int cpu_flags = av_get_cpu_flags();
|
||||
|
||||
#if HAVE_INLINE_ASM
|
||||
#if HAVE_MMX2
|
||||
if (cpu_flags & AV_CPU_FLAG_MMX2)
|
||||
gf->filter_line = gradfun_filter_line_mmx2;
|
||||
@ -180,4 +185,5 @@ av_cold void ff_gradfun_init_x86(GradFunContext *gf)
|
||||
if (cpu_flags & AV_CPU_FLAG_SSE2)
|
||||
gf->blur_line = gradfun_blur_line_sse2;
|
||||
#endif
|
||||
#endif /* HAVE_INLINE_ASM */
|
||||
}
|
||||
|
@ -24,6 +24,8 @@
|
||||
#include "libavcodec/x86/dsputil_mmx.h"
|
||||
#include "libavfilter/yadif.h"
|
||||
|
||||
#if HAVE_INLINE_ASM
|
||||
|
||||
DECLARE_ASM_CONST(16, const xmm_reg, pb_1) = {0x0101010101010101ULL, 0x0101010101010101ULL};
|
||||
DECLARE_ASM_CONST(16, const xmm_reg, pw_1) = {0x0001000100010001ULL, 0x0001000100010001ULL};
|
||||
|
||||
@ -49,10 +51,13 @@ DECLARE_ASM_CONST(16, const xmm_reg, pw_1) = {0x0001000100010001ULL, 0x000100010
|
||||
#include "yadif_template.c"
|
||||
#endif
|
||||
|
||||
#endif /* HAVE_INLINE_ASM */
|
||||
|
||||
av_cold void ff_yadif_init_x86(YADIFContext *yadif)
|
||||
{
|
||||
int cpu_flags = av_get_cpu_flags();
|
||||
|
||||
#if HAVE_INLINE_ASM
|
||||
#if HAVE_MMX
|
||||
if (cpu_flags & AV_CPU_FLAG_MMX)
|
||||
yadif->filter_line = yadif_filter_line_mmx;
|
||||
@ -65,4 +70,5 @@ av_cold void ff_yadif_init_x86(YADIFContext *yadif)
|
||||
if (cpu_flags & AV_CPU_FLAG_SSSE3)
|
||||
yadif->filter_line = yadif_filter_line_ssse3;
|
||||
#endif
|
||||
#endif /* HAVE_INLINE_ASM */
|
||||
}
|
||||
|
@ -374,6 +374,7 @@ OBJS-$(CONFIG_BLURAY_PROTOCOL) += bluray.o
|
||||
OBJS-$(CONFIG_CACHE_PROTOCOL) += cache.o
|
||||
OBJS-$(CONFIG_CONCAT_PROTOCOL) += concat.o
|
||||
OBJS-$(CONFIG_CRYPTO_PROTOCOL) += crypto.o
|
||||
OBJS-$(CONFIG_FFRTMPCRYPT_PROTOCOL) += rtmpcrypt.o rtmpdh.o
|
||||
OBJS-$(CONFIG_FFRTMPHTTP_PROTOCOL) += rtmphttp.o
|
||||
OBJS-$(CONFIG_FILE_PROTOCOL) += file.o
|
||||
OBJS-$(CONFIG_GOPHER_PROTOCOL) += gopher.o
|
||||
@ -386,8 +387,10 @@ OBJS-$(CONFIG_MMST_PROTOCOL) += mmst.o mms.o asf.o
|
||||
OBJS-$(CONFIG_MD5_PROTOCOL) += md5proto.o
|
||||
OBJS-$(CONFIG_PIPE_PROTOCOL) += file.o
|
||||
OBJS-$(CONFIG_RTMP_PROTOCOL) += rtmpproto.o rtmppkt.o
|
||||
OBJS-$(CONFIG_RTMPE_PROTOCOL) += rtmpproto.o rtmppkt.o
|
||||
OBJS-$(CONFIG_RTMPS_PROTOCOL) += rtmpproto.o rtmppkt.o
|
||||
OBJS-$(CONFIG_RTMPT_PROTOCOL) += rtmpproto.o rtmppkt.o
|
||||
OBJS-$(CONFIG_RTMPTE_PROTOCOL) += rtmpproto.o rtmppkt.o
|
||||
OBJS-$(CONFIG_RTMPTS_PROTOCOL) += rtmpproto.o rtmppkt.o
|
||||
OBJS-$(CONFIG_RTP_PROTOCOL) += rtpproto.o
|
||||
OBJS-$(CONFIG_SCTP_PROTOCOL) += sctp.o
|
||||
|
@ -272,6 +272,7 @@ void av_register_all(void)
|
||||
REGISTER_PROTOCOL (CACHE, cache);
|
||||
REGISTER_PROTOCOL (CONCAT, concat);
|
||||
REGISTER_PROTOCOL (CRYPTO, crypto);
|
||||
REGISTER_PROTOCOL (FFRTMPCRYPT, ffrtmpcrypt);
|
||||
REGISTER_PROTOCOL (FFRTMPHTTP, ffrtmphttp);
|
||||
REGISTER_PROTOCOL (FILE, file);
|
||||
REGISTER_PROTOCOL (GOPHER, gopher);
|
||||
@ -284,8 +285,10 @@ void av_register_all(void)
|
||||
REGISTER_PROTOCOL (MD5, md5);
|
||||
REGISTER_PROTOCOL (PIPE, pipe);
|
||||
REGISTER_PROTOCOL (RTMP, rtmp);
|
||||
REGISTER_PROTOCOL (RTMPE, rtmpe);
|
||||
REGISTER_PROTOCOL (RTMPS, rtmps);
|
||||
REGISTER_PROTOCOL (RTMPT, rtmpt);
|
||||
REGISTER_PROTOCOL (RTMPTE, rtmpte);
|
||||
REGISTER_PROTOCOL (RTMPTS, rtmpts);
|
||||
REGISTER_PROTOCOL (RTP, rtp);
|
||||
REGISTER_PROTOCOL (SCTP, sctp);
|
||||
|
@ -654,11 +654,7 @@ AVOutputFormat ff_avi_muxer = {
|
||||
.mime_type = "video/x-msvideo",
|
||||
.extensions = "avi",
|
||||
.priv_data_size = sizeof(AVIContext),
|
||||
#if CONFIG_LIBMP3LAME_ENCODER
|
||||
.audio_codec = CODEC_ID_MP3,
|
||||
#else
|
||||
.audio_codec = CODEC_ID_AC3,
|
||||
#endif
|
||||
.audio_codec = CONFIG_LIBMP3LAME ? CODEC_ID_MP3 : CODEC_ID_AC3,
|
||||
.video_codec = CODEC_ID_MPEG4,
|
||||
.write_header = avi_write_header,
|
||||
.write_packet = avi_write_packet,
|
||||
|
@ -570,11 +570,7 @@ AVOutputFormat ff_flv_muxer = {
|
||||
.mime_type = "video/x-flv",
|
||||
.extensions = "flv",
|
||||
.priv_data_size = sizeof(FLVContext),
|
||||
#if CONFIG_LIBMP3LAME
|
||||
.audio_codec = CODEC_ID_MP3,
|
||||
#else // CONFIG_LIBMP3LAME
|
||||
.audio_codec = CODEC_ID_ADPCM_SWF,
|
||||
#endif // CONFIG_LIBMP3LAME
|
||||
.audio_codec = CONFIG_LIBMP3LAME ? CODEC_ID_MP3 : CODEC_ID_ADPCM_SWF,
|
||||
.video_codec = CODEC_ID_FLV1,
|
||||
.write_header = flv_write_header,
|
||||
.write_packet = flv_write_packet,
|
||||
|
@ -1311,16 +1311,10 @@ AVOutputFormat ff_matroska_muxer = {
|
||||
.mime_type = "video/x-matroska",
|
||||
.extensions = "mkv",
|
||||
.priv_data_size = sizeof(MatroskaMuxContext),
|
||||
#if CONFIG_LIBVORBIS_ENCODER
|
||||
.audio_codec = CODEC_ID_VORBIS,
|
||||
#else
|
||||
.audio_codec = CODEC_ID_AC3,
|
||||
#endif
|
||||
#if CONFIG_LIBX264_ENCODER
|
||||
.video_codec = CODEC_ID_H264,
|
||||
#else
|
||||
.video_codec = CODEC_ID_MPEG4,
|
||||
#endif
|
||||
.audio_codec = CONFIG_LIBVORBIS_ENCODER ?
|
||||
CODEC_ID_VORBIS : CODEC_ID_AC3,
|
||||
.video_codec = CONFIG_LIBX264_ENCODER ?
|
||||
CODEC_ID_H264 : CODEC_ID_MPEG4,
|
||||
.write_header = mkv_write_header,
|
||||
.write_packet = mkv_write_packet,
|
||||
.write_trailer = mkv_write_trailer,
|
||||
@ -1355,11 +1349,8 @@ AVOutputFormat ff_matroska_audio_muxer = {
|
||||
.mime_type = "audio/x-matroska",
|
||||
.extensions = "mka",
|
||||
.priv_data_size = sizeof(MatroskaMuxContext),
|
||||
#if CONFIG_LIBVORBIS_ENCODER
|
||||
.audio_codec = CODEC_ID_VORBIS,
|
||||
#else
|
||||
.audio_codec = CODEC_ID_AC3,
|
||||
#endif
|
||||
.audio_codec = CONFIG_LIBVORBIS_ENCODER ?
|
||||
CODEC_ID_VORBIS : CODEC_ID_AC3,
|
||||
.video_codec = CODEC_ID_NONE,
|
||||
.write_header = mkv_write_header,
|
||||
.write_packet = mkv_write_packet,
|
||||
|
@ -3584,11 +3584,8 @@ AVOutputFormat ff_mov_muxer = {
|
||||
.extensions = "mov",
|
||||
.priv_data_size = sizeof(MOVMuxContext),
|
||||
.audio_codec = CODEC_ID_AAC,
|
||||
#if CONFIG_LIBX264_ENCODER
|
||||
.video_codec = CODEC_ID_H264,
|
||||
#else
|
||||
.video_codec = CODEC_ID_MPEG4,
|
||||
#endif
|
||||
.video_codec = CONFIG_LIBX264_ENCODER ?
|
||||
CODEC_ID_H264 : CODEC_ID_MPEG4,
|
||||
.write_header = mov_write_header,
|
||||
.write_packet = mov_write_packet,
|
||||
.write_trailer = mov_write_trailer,
|
||||
@ -3625,11 +3622,8 @@ AVOutputFormat ff_mp4_muxer = {
|
||||
.extensions = "mp4",
|
||||
.priv_data_size = sizeof(MOVMuxContext),
|
||||
.audio_codec = CODEC_ID_AAC,
|
||||
#if CONFIG_LIBX264_ENCODER
|
||||
.video_codec = CODEC_ID_H264,
|
||||
#else
|
||||
.video_codec = CODEC_ID_MPEG4,
|
||||
#endif
|
||||
.video_codec = CONFIG_LIBX264_ENCODER ?
|
||||
CODEC_ID_H264 : CODEC_ID_MPEG4,
|
||||
.write_header = mov_write_header,
|
||||
.write_packet = mov_write_packet,
|
||||
.write_trailer = mov_write_trailer,
|
||||
@ -3646,11 +3640,8 @@ AVOutputFormat ff_psp_muxer = {
|
||||
.extensions = "mp4,psp",
|
||||
.priv_data_size = sizeof(MOVMuxContext),
|
||||
.audio_codec = CODEC_ID_AAC,
|
||||
#if CONFIG_LIBX264_ENCODER
|
||||
.video_codec = CODEC_ID_H264,
|
||||
#else
|
||||
.video_codec = CODEC_ID_MPEG4,
|
||||
#endif
|
||||
.video_codec = CONFIG_LIBX264_ENCODER ?
|
||||
CODEC_ID_H264 : CODEC_ID_MPEG4,
|
||||
.write_header = mov_write_header,
|
||||
.write_packet = mov_write_packet,
|
||||
.write_trailer = mov_write_trailer,
|
||||
|
@ -870,13 +870,8 @@ AVOutputFormat ff_nut_muxer = {
|
||||
.mime_type = "video/x-nut",
|
||||
.extensions = "nut",
|
||||
.priv_data_size = sizeof(NUTContext),
|
||||
#if CONFIG_LIBVORBIS
|
||||
.audio_codec = CODEC_ID_VORBIS,
|
||||
#elif CONFIG_LIBMP3LAME
|
||||
.audio_codec = CODEC_ID_MP3,
|
||||
#else
|
||||
.audio_codec = CODEC_ID_MP2,
|
||||
#endif
|
||||
.audio_codec = CONFIG_LIBVORBIS ? CODEC_ID_VORBIS :
|
||||
CONFIG_LIBMP3LAME ? CODEC_ID_MP3 : CODEC_ID_MP2,
|
||||
.video_codec = CODEC_ID_MPEG4,
|
||||
.write_header = nut_write_header,
|
||||
.write_packet = nut_write_packet,
|
||||
|
@ -29,6 +29,9 @@
|
||||
|
||||
#define RTMP_HANDSHAKE_PACKET_SIZE 1536
|
||||
|
||||
#define HMAC_IPAD_VAL 0x36
|
||||
#define HMAC_OPAD_VAL 0x5C
|
||||
|
||||
/**
|
||||
* emulated Flash client version - 9.0.124.2 on Linux
|
||||
* @{
|
||||
@ -40,4 +43,29 @@
|
||||
#define RTMP_CLIENT_VER4 2
|
||||
/** @} */ //version defines
|
||||
|
||||
/**
|
||||
* Calculate HMAC-SHA2 digest for RTMP handshake packets.
|
||||
*
|
||||
* @param src input buffer
|
||||
* @param len input buffer length (should be 1536)
|
||||
* @param gap offset in buffer where 32 bytes should not be taken into account
|
||||
* when calculating digest (since it will be used to store that digest)
|
||||
* @param key digest key
|
||||
* @param keylen digest key length
|
||||
* @param dst buffer where calculated digest will be stored (32 bytes)
|
||||
*/
|
||||
int ff_rtmp_calc_digest(const uint8_t *src, int len, int gap,
|
||||
const uint8_t *key, int keylen, uint8_t *dst);
|
||||
|
||||
/**
|
||||
* Calculate digest position for RTMP handshake packets.
|
||||
*
|
||||
* @param buf input buffer (should be 1536 bytes)
|
||||
* @param off offset in buffer where to start calculating digest position
|
||||
* @param mod_val value used for computing modulo
|
||||
* @param add_val value added at the end (after computing modulo)
|
||||
*/
|
||||
int ff_rtmp_calc_digest_pos(const uint8_t *buf, int off, int mod_val,
|
||||
int add_val);
|
||||
|
||||
#endif /* AVFORMAT_RTMP_H */
|
||||
|
334
libavformat/rtmpcrypt.c
Normal file
334
libavformat/rtmpcrypt.c
Normal file
@ -0,0 +1,334 @@
|
||||
/*
|
||||
* RTMPE network protocol
|
||||
* Copyright (c) 2012 Samuel Pitoiset
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* RTMPE protocol
|
||||
*/
|
||||
|
||||
#include "libavutil/blowfish.h"
|
||||
#include "libavutil/intreadwrite.h"
|
||||
#include "libavutil/opt.h"
|
||||
#include "libavutil/rc4.h"
|
||||
#include "libavutil/xtea.h"
|
||||
|
||||
#include "internal.h"
|
||||
#include "rtmp.h"
|
||||
#include "rtmpdh.h"
|
||||
#include "rtmpcrypt.h"
|
||||
#include "url.h"
|
||||
|
||||
/* protocol handler context */
|
||||
typedef struct RTMPEContext {
|
||||
const AVClass *class;
|
||||
URLContext *stream; ///< TCP stream
|
||||
FF_DH *dh; ///< Diffie-Hellman context
|
||||
struct AVRC4 key_in; ///< RC4 key used for decrypt data
|
||||
struct AVRC4 key_out; ///< RC4 key used for encrypt data
|
||||
int handshaked; ///< flag indicating when the handshake is performed
|
||||
int tunneling; ///< use a HTTP connection (RTMPTE)
|
||||
} RTMPEContext;
|
||||
|
||||
static const uint8_t rtmpe8_keys[16][16] = {
|
||||
{ 0xbf, 0xf0, 0x34, 0xb2, 0x11, 0xd9, 0x08, 0x1f,
|
||||
0xcc, 0xdf, 0xb7, 0x95, 0x74, 0x8d, 0xe7, 0x32 },
|
||||
{ 0x08, 0x6a, 0x5e, 0xb6, 0x17, 0x43, 0x09, 0x0e,
|
||||
0x6e, 0xf0, 0x5a, 0xb8, 0xfe, 0x5a, 0x39, 0xe2 },
|
||||
{ 0x7b, 0x10, 0x95, 0x6f, 0x76, 0xce, 0x05, 0x21,
|
||||
0x23, 0x88, 0xa7, 0x3a, 0x44, 0x01, 0x49, 0xa1 },
|
||||
{ 0xa9, 0x43, 0xf3, 0x17, 0xeb, 0xf1, 0x1b, 0xb2,
|
||||
0xa6, 0x91, 0xa5, 0xee, 0x17, 0xf3, 0x63, 0x39 },
|
||||
{ 0x7a, 0x30, 0xe0, 0x0a, 0xb5, 0x29, 0xe2, 0x2c,
|
||||
0xa0, 0x87, 0xae, 0xa5, 0xc0, 0xcb, 0x79, 0xac },
|
||||
{ 0xbd, 0xce, 0x0c, 0x23, 0x2f, 0xeb, 0xde, 0xff,
|
||||
0x1c, 0xfa, 0xae, 0x16, 0x11, 0x23, 0x23, 0x9d },
|
||||
{ 0x55, 0xdd, 0x3f, 0x7b, 0x77, 0xe7, 0xe6, 0x2e,
|
||||
0x9b, 0xb8, 0xc4, 0x99, 0xc9, 0x48, 0x1e, 0xe4 },
|
||||
{ 0x40, 0x7b, 0xb6, 0xb4, 0x71, 0xe8, 0x91, 0x36,
|
||||
0xa7, 0xae, 0xbf, 0x55, 0xca, 0x33, 0xb8, 0x39 },
|
||||
{ 0xfc, 0xf6, 0xbd, 0xc3, 0xb6, 0x3c, 0x36, 0x97,
|
||||
0x7c, 0xe4, 0xf8, 0x25, 0x04, 0xd9, 0x59, 0xb2 },
|
||||
{ 0x28, 0xe0, 0x91, 0xfd, 0x41, 0x95, 0x4c, 0x4c,
|
||||
0x7f, 0xb7, 0xdb, 0x00, 0xe3, 0xa0, 0x66, 0xf8 },
|
||||
{ 0x57, 0x84, 0x5b, 0x76, 0x4f, 0x25, 0x1b, 0x03,
|
||||
0x46, 0xd4, 0x5b, 0xcd, 0xa2, 0xc3, 0x0d, 0x29 },
|
||||
{ 0x0a, 0xcc, 0xee, 0xf8, 0xda, 0x55, 0xb5, 0x46,
|
||||
0x03, 0x47, 0x34, 0x52, 0x58, 0x63, 0x71, 0x3b },
|
||||
{ 0xb8, 0x20, 0x75, 0xdc, 0xa7, 0x5f, 0x1f, 0xee,
|
||||
0xd8, 0x42, 0x68, 0xe8, 0xa7, 0x2a, 0x44, 0xcc },
|
||||
{ 0x07, 0xcf, 0x6e, 0x9e, 0xa1, 0x6d, 0x7b, 0x25,
|
||||
0x9f, 0xa7, 0xae, 0x6c, 0xd9, 0x2f, 0x56, 0x29 },
|
||||
{ 0xfe, 0xb1, 0xea, 0xe4, 0x8c, 0x8c, 0x3c, 0xe1,
|
||||
0x4e, 0x00, 0x64, 0xa7, 0x6a, 0x38, 0x7c, 0x2a },
|
||||
{ 0x89, 0x3a, 0x94, 0x27, 0xcc, 0x30, 0x13, 0xa2,
|
||||
0xf1, 0x06, 0x38, 0x5b, 0xa8, 0x29, 0xf9, 0x27 }
|
||||
};
|
||||
|
||||
static const uint8_t rtmpe9_keys[16][24] = {
|
||||
{ 0x79, 0x34, 0x77, 0x4c, 0x67, 0xd1, 0x38, 0x3a, 0xdf, 0xb3, 0x56, 0xbe,
|
||||
0x8b, 0x7b, 0xd0, 0x24, 0x38, 0xe0, 0x73, 0x58, 0x41, 0x5d, 0x69, 0x67, },
|
||||
{ 0x46, 0xf6, 0xb4, 0xcc, 0x01, 0x93, 0xe3, 0xa1, 0x9e, 0x7d, 0x3c, 0x65,
|
||||
0x55, 0x86, 0xfd, 0x09, 0x8f, 0xf7, 0xb3, 0xc4, 0x6f, 0x41, 0xca, 0x5c, },
|
||||
{ 0x1a, 0xe7, 0xe2, 0xf3, 0xf9, 0x14, 0x79, 0x94, 0xc0, 0xd3, 0x97, 0x43,
|
||||
0x08, 0x7b, 0xb3, 0x84, 0x43, 0x2f, 0x9d, 0x84, 0x3f, 0x21, 0x01, 0x9b, },
|
||||
{ 0xd3, 0xe3, 0x54, 0xb0, 0xf7, 0x1d, 0xf6, 0x2b, 0x5a, 0x43, 0x4d, 0x04,
|
||||
0x83, 0x64, 0x3e, 0x0d, 0x59, 0x2f, 0x61, 0xcb, 0xb1, 0x6a, 0x59, 0x0d, },
|
||||
{ 0xc8, 0xc1, 0xe9, 0xb8, 0x16, 0x56, 0x99, 0x21, 0x7b, 0x5b, 0x36, 0xb7,
|
||||
0xb5, 0x9b, 0xdf, 0x06, 0x49, 0x2c, 0x97, 0xf5, 0x95, 0x48, 0x85, 0x7e, },
|
||||
{ 0xeb, 0xe5, 0xe6, 0x2e, 0xa4, 0xba, 0xd4, 0x2c, 0xf2, 0x16, 0xe0, 0x8f,
|
||||
0x66, 0x23, 0xa9, 0x43, 0x41, 0xce, 0x38, 0x14, 0x84, 0x95, 0x00, 0x53, },
|
||||
{ 0x66, 0xdb, 0x90, 0xf0, 0x3b, 0x4f, 0xf5, 0x6f, 0xe4, 0x9c, 0x20, 0x89,
|
||||
0x35, 0x5e, 0xd2, 0xb2, 0xc3, 0x9e, 0x9f, 0x7f, 0x63, 0xb2, 0x28, 0x81, },
|
||||
{ 0xbb, 0x20, 0xac, 0xed, 0x2a, 0x04, 0x6a, 0x19, 0x94, 0x98, 0x9b, 0xc8,
|
||||
0xff, 0xcd, 0x93, 0xef, 0xc6, 0x0d, 0x56, 0xa7, 0xeb, 0x13, 0xd9, 0x30, },
|
||||
{ 0xbc, 0xf2, 0x43, 0x82, 0x09, 0x40, 0x8a, 0x87, 0x25, 0x43, 0x6d, 0xe6,
|
||||
0xbb, 0xa4, 0xb9, 0x44, 0x58, 0x3f, 0x21, 0x7c, 0x99, 0xbb, 0x3f, 0x24, },
|
||||
{ 0xec, 0x1a, 0xaa, 0xcd, 0xce, 0xbd, 0x53, 0x11, 0xd2, 0xfb, 0x83, 0xb6,
|
||||
0xc3, 0xba, 0xab, 0x4f, 0x62, 0x79, 0xe8, 0x65, 0xa9, 0x92, 0x28, 0x76, },
|
||||
{ 0xc6, 0x0c, 0x30, 0x03, 0x91, 0x18, 0x2d, 0x7b, 0x79, 0xda, 0xe1, 0xd5,
|
||||
0x64, 0x77, 0x9a, 0x12, 0xc5, 0xb1, 0xd7, 0x91, 0x4f, 0x96, 0x4c, 0xa3, },
|
||||
{ 0xd7, 0x7c, 0x2a, 0xbf, 0xa6, 0xe7, 0x85, 0x7c, 0x45, 0xad, 0xff, 0x12,
|
||||
0x94, 0xd8, 0xde, 0xa4, 0x5c, 0x3d, 0x79, 0xa4, 0x44, 0x02, 0x5d, 0x22, },
|
||||
{ 0x16, 0x19, 0x0d, 0x81, 0x6a, 0x4c, 0xc7, 0xf8, 0xb8, 0xf9, 0x4e, 0xcd,
|
||||
0x2c, 0x9e, 0x90, 0x84, 0xb2, 0x08, 0x25, 0x60, 0xe1, 0x1e, 0xae, 0x18, },
|
||||
{ 0xe9, 0x7c, 0x58, 0x26, 0x1b, 0x51, 0x9e, 0x49, 0x82, 0x60, 0x61, 0xfc,
|
||||
0xa0, 0xa0, 0x1b, 0xcd, 0xf5, 0x05, 0xd6, 0xa6, 0x6d, 0x07, 0x88, 0xa3, },
|
||||
{ 0x2b, 0x97, 0x11, 0x8b, 0xd9, 0x4e, 0xd9, 0xdf, 0x20, 0xe3, 0x9c, 0x10,
|
||||
0xe6, 0xa1, 0x35, 0x21, 0x11, 0xf9, 0x13, 0x0d, 0x0b, 0x24, 0x65, 0xb2, },
|
||||
{ 0x53, 0x6a, 0x4c, 0x54, 0xac, 0x8b, 0x9b, 0xb8, 0x97, 0x29, 0xfc, 0x60,
|
||||
0x2c, 0x5b, 0x3a, 0x85, 0x68, 0xb5, 0xaa, 0x6a, 0x44, 0xcd, 0x3f, 0xa7, },
|
||||
};
|
||||
|
||||
int ff_rtmpe_gen_pub_key(URLContext *h, uint8_t *buf)
|
||||
{
|
||||
RTMPEContext *rt = h->priv_data;
|
||||
int offset, ret;
|
||||
|
||||
if (!(rt->dh = ff_dh_init(1024)))
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
offset = ff_rtmp_calc_digest_pos(buf, 768, 632, 8);
|
||||
if (offset < 0)
|
||||
return offset;
|
||||
|
||||
/* generate a Diffie-Hellmann public key */
|
||||
if ((ret = ff_dh_generate_public_key(rt->dh)) < 0)
|
||||
return ret;
|
||||
|
||||
/* write the public key into the handshake buffer */
|
||||
if ((ret = ff_dh_write_public_key(rt->dh, buf + offset, 128)) < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ff_rtmpe_compute_secret_key(URLContext *h, const uint8_t *serverdata,
|
||||
const uint8_t *clientdata, int type)
|
||||
{
|
||||
RTMPEContext *rt = h->priv_data;
|
||||
uint8_t secret_key[128], digest[32];
|
||||
int server_pos, client_pos;
|
||||
int ret;
|
||||
|
||||
if (type) {
|
||||
if ((server_pos = ff_rtmp_calc_digest_pos(serverdata, 1532, 632, 772)) < 0)
|
||||
return server_pos;
|
||||
} else {
|
||||
if ((server_pos = ff_rtmp_calc_digest_pos(serverdata, 768, 632, 8)) < 0)
|
||||
return server_pos;
|
||||
}
|
||||
|
||||
if ((client_pos = ff_rtmp_calc_digest_pos(clientdata, 768, 632, 8)) < 0)
|
||||
return client_pos;
|
||||
|
||||
/* compute the shared secret secret in order to compute RC4 keys */
|
||||
if ((ret = ff_dh_compute_shared_secret_key(rt->dh, serverdata + server_pos,
|
||||
128, secret_key)) < 0)
|
||||
return ret;
|
||||
|
||||
/* set output key */
|
||||
if ((ret = ff_rtmp_calc_digest(serverdata + server_pos, 128, 0, secret_key,
|
||||
128, digest)) < 0)
|
||||
return ret;
|
||||
av_rc4_init(&rt->key_out, digest, 16 * 8, 1);
|
||||
|
||||
/* set input key */
|
||||
if ((ret = ff_rtmp_calc_digest(clientdata + client_pos, 128, 0, secret_key,
|
||||
128, digest)) < 0)
|
||||
return ret;
|
||||
av_rc4_init(&rt->key_in, digest, 16 * 8, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rtmpe8_sig(const uint8_t *in, uint8_t *out, int key_id)
|
||||
{
|
||||
struct AVXTEA ctx;
|
||||
|
||||
av_xtea_init(&ctx, rtmpe8_keys[key_id]);
|
||||
av_xtea_crypt(&ctx, out, in, 1, NULL, 0);
|
||||
}
|
||||
|
||||
static void rtmpe9_sig(const uint8_t *in, uint8_t *out, int key_id)
|
||||
{
|
||||
struct AVBlowfish ctx;
|
||||
uint32_t xl, xr;
|
||||
|
||||
xl = AV_RL32(in);
|
||||
xr = AV_RL32(in + 4);
|
||||
|
||||
av_blowfish_init(&ctx, rtmpe9_keys[key_id], 24);
|
||||
av_blowfish_crypt_ecb(&ctx, &xl, &xr, 0);
|
||||
|
||||
AV_WL32(out, xl);
|
||||
AV_WL32(out + 4, xr);
|
||||
}
|
||||
|
||||
void ff_rtmpe_encrypt_sig(URLContext *h, uint8_t *sig, const uint8_t *digest,
|
||||
int type)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 32; i += 8) {
|
||||
if (type == 8) {
|
||||
/* RTMPE type 8 uses XTEA on the signature */
|
||||
rtmpe8_sig(sig + i, sig + i, digest[i] % 15);
|
||||
} else if (type == 9) {
|
||||
/* RTMPE type 9 uses Blowfish on the signature */
|
||||
rtmpe9_sig(sig + i, sig + i, digest[i] % 15);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int ff_rtmpe_update_keystream(URLContext *h)
|
||||
{
|
||||
RTMPEContext *rt = h->priv_data;
|
||||
char buf[RTMP_HANDSHAKE_PACKET_SIZE];
|
||||
|
||||
/* skip past 1536 bytes of the RC4 bytestream */
|
||||
av_rc4_crypt(&rt->key_in, buf, NULL, sizeof(buf), NULL, 1);
|
||||
av_rc4_crypt(&rt->key_out, buf, NULL, sizeof(buf), NULL, 1);
|
||||
|
||||
/* the next requests will be encrypted using RC4 keys */
|
||||
rt->handshaked = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rtmpe_close(URLContext *h)
|
||||
{
|
||||
RTMPEContext *rt = h->priv_data;
|
||||
|
||||
ff_dh_free(rt->dh);
|
||||
ffurl_close(rt->stream);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rtmpe_open(URLContext *h, const char *uri, int flags)
|
||||
{
|
||||
RTMPEContext *rt = h->priv_data;
|
||||
char host[256], url[1024];
|
||||
int ret, port;
|
||||
|
||||
av_url_split(NULL, 0, NULL, 0, host, sizeof(host), &port, NULL, 0, uri);
|
||||
|
||||
if (rt->tunneling) {
|
||||
if (port < 0)
|
||||
port = 80;
|
||||
ff_url_join(url, sizeof(url), "ffrtmphttp", NULL, host, port, NULL);
|
||||
} else {
|
||||
if (port < 0)
|
||||
port = 1935;
|
||||
ff_url_join(url, sizeof(url), "tcp", NULL, host, port, NULL);
|
||||
}
|
||||
|
||||
/* open the tcp or ffrtmphttp connection */
|
||||
if ((ret = ffurl_open(&rt->stream, url, AVIO_FLAG_READ_WRITE,
|
||||
&h->interrupt_callback, NULL)) < 0) {
|
||||
rtmpe_close(h);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rtmpe_read(URLContext *h, uint8_t *buf, int size)
|
||||
{
|
||||
RTMPEContext *rt = h->priv_data;
|
||||
int ret;
|
||||
|
||||
rt->stream->flags |= h->flags & AVIO_FLAG_NONBLOCK;
|
||||
ret = ffurl_read(rt->stream, buf, size);
|
||||
rt->stream->flags &= ~AVIO_FLAG_NONBLOCK;
|
||||
|
||||
if (ret < 0 && ret != AVERROR_EOF)
|
||||
return ret;
|
||||
|
||||
if (rt->handshaked && ret > 0) {
|
||||
/* decrypt data received by the server */
|
||||
av_rc4_crypt(&rt->key_in, buf, buf, ret, NULL, 1);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rtmpe_write(URLContext *h, const uint8_t *buf, int size)
|
||||
{
|
||||
RTMPEContext *rt = h->priv_data;
|
||||
int ret;
|
||||
|
||||
if (rt->handshaked) {
|
||||
/* encrypt data to send to the server */
|
||||
av_rc4_crypt(&rt->key_out, buf, buf, size, NULL, 1);
|
||||
}
|
||||
|
||||
if ((ret = ffurl_write(rt->stream, buf, size)) < 0)
|
||||
return ret;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
#define OFFSET(x) offsetof(RTMPEContext, x)
|
||||
#define DEC AV_OPT_FLAG_DECODING_PARAM
|
||||
|
||||
static const AVOption ffrtmpcrypt_options[] = {
|
||||
{"ffrtmpcrypt_tunneling", "Use a HTTP tunneling connection (RTMPTE).", OFFSET(tunneling), AV_OPT_TYPE_INT, {0}, 0, 1, DEC},
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
static const AVClass ffrtmpcrypt_class = {
|
||||
.class_name = "ffrtmpcrypt",
|
||||
.item_name = av_default_item_name,
|
||||
.option = ffrtmpcrypt_options,
|
||||
.version = LIBAVUTIL_VERSION_INT,
|
||||
};
|
||||
|
||||
URLProtocol ff_ffrtmpcrypt_protocol = {
|
||||
.name = "ffrtmpcrypt",
|
||||
.url_open = rtmpe_open,
|
||||
.url_read = rtmpe_read,
|
||||
.url_write = rtmpe_write,
|
||||
.url_close = rtmpe_close,
|
||||
.priv_data_size = sizeof(RTMPEContext),
|
||||
.flags = URL_PROTOCOL_FLAG_NETWORK,
|
||||
.priv_data_class = &ffrtmpcrypt_class,
|
||||
};
|
69
libavformat/rtmpcrypt.h
Normal file
69
libavformat/rtmpcrypt.h
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* RTMPE encryption utilities
|
||||
* Copyright (c) 2012 Samuel Pitoiset
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef AVFORMAT_RTMPCRYPT_H
|
||||
#define AVFORMAT_RTMPCRYPT_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "url.h"
|
||||
|
||||
/**
|
||||
* Initialize the Diffie-Hellmann context and generate the public key.
|
||||
*
|
||||
* @param h an URLContext
|
||||
* @param buf handshake data (1536 bytes)
|
||||
* @return zero on success, negative value otherwise
|
||||
*/
|
||||
int ff_rtmpe_gen_pub_key(URLContext *h, uint8_t *buf);
|
||||
|
||||
/**
|
||||
* Compute the shared secret key and initialize the RC4 encryption.
|
||||
*
|
||||
* @param h an URLContext
|
||||
* @param serverdata server data (1536 bytes)
|
||||
* @param clientdata client data (1536 bytes)
|
||||
* @param type the position of the server digest
|
||||
* @return zero on success, negative value otherwise
|
||||
*/
|
||||
int ff_rtmpe_compute_secret_key(URLContext *h, const uint8_t *serverdata,
|
||||
const uint8_t *clientdata, int type);
|
||||
|
||||
/**
|
||||
* Encrypt the signature.
|
||||
*
|
||||
* @param h an URLContext
|
||||
* @param signature the signature to encrypt
|
||||
* @param digest the digest used for finding the encryption key
|
||||
* @param type type of encryption (8 for XTEA, 9 for Blowfish)
|
||||
*/
|
||||
void ff_rtmpe_encrypt_sig(URLContext *h, uint8_t *signature,
|
||||
const uint8_t *digest, int type);
|
||||
|
||||
/**
|
||||
* Update the keystream and set RC4 keys for encryption.
|
||||
*
|
||||
* @param h an URLContext
|
||||
* @return zero on success, negative value otherwise
|
||||
*/
|
||||
int ff_rtmpe_update_keystream(URLContext *h);
|
||||
|
||||
#endif /* AVFORMAT_RTMPCRYPT_H */
|
329
libavformat/rtmpdh.c
Normal file
329
libavformat/rtmpdh.c
Normal file
@ -0,0 +1,329 @@
|
||||
/*
|
||||
* RTMP Diffie-Hellmann utilities
|
||||
* Copyright (c) 2012 Samuel Pitoiset
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* RTMP Diffie-Hellmann utilities
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "rtmpdh.h"
|
||||
|
||||
#define P1024 \
|
||||
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \
|
||||
"29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \
|
||||
"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \
|
||||
"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \
|
||||
"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381" \
|
||||
"FFFFFFFFFFFFFFFF"
|
||||
|
||||
#define Q1024 \
|
||||
"7FFFFFFFFFFFFFFFE487ED5110B4611A62633145C06E0E68" \
|
||||
"948127044533E63A0105DF531D89CD9128A5043CC71A026E" \
|
||||
"F7CA8CD9E69D218D98158536F92F8A1BA7F09AB6B6A8E122" \
|
||||
"F242DABB312F3F637A262174D31BF6B585FFAE5B7A035BF6" \
|
||||
"F71C35FDAD44CFD2D74F9208BE258FF324943328F67329C0" \
|
||||
"FFFFFFFFFFFFFFFF"
|
||||
|
||||
#if CONFIG_NETTLE || CONFIG_GCRYPT
|
||||
#if CONFIG_NETTLE
|
||||
#define bn_new(bn) \
|
||||
do { \
|
||||
bn = av_malloc(sizeof(*bn)); \
|
||||
if (bn) \
|
||||
mpz_init2(bn, 1); \
|
||||
} while (0)
|
||||
#define bn_free(bn) \
|
||||
do { \
|
||||
mpz_clear(bn); \
|
||||
av_free(bn); \
|
||||
} while (0)
|
||||
#define bn_set_word(bn, w) mpz_set_ui(bn, w)
|
||||
#define bn_cmp(a, b) mpz_cmp(a, b)
|
||||
#define bn_copy(to, from) mpz_set(to, from)
|
||||
#define bn_sub_word(bn, w) mpz_sub_ui(bn, bn, w)
|
||||
#define bn_cmp_1(bn) mpz_cmp_ui(bn, 1)
|
||||
#define bn_num_bytes(bn) (mpz_sizeinbase(bn, 2) + 7) / 8
|
||||
#define bn_bn2bin(bn, buf, len) nettle_mpz_get_str_256(len, buf, bn)
|
||||
#define bn_bin2bn(bn, buf, len) \
|
||||
do { \
|
||||
bn_new(bn); \
|
||||
if (bn) \
|
||||
nettle_mpz_set_str_256_u(bn, len, buf); \
|
||||
} while (0)
|
||||
#define bn_hex2bn(bn, buf, ret) \
|
||||
do { \
|
||||
bn_new(bn); \
|
||||
if (bn) \
|
||||
ret = (mpz_set_str(bn, buf, 16) == 0); \
|
||||
} while (0)
|
||||
#define bn_modexp(bn, y, q, p) mpz_powm(bn, y, q, p)
|
||||
#define bn_random(bn, num_bytes) mpz_random(bn, num_bytes);
|
||||
#elif CONFIG_GCRYPT
|
||||
#define bn_new(bn) bn = gcry_mpi_new(1)
|
||||
#define bn_free(bn) gcry_mpi_release(bn)
|
||||
#define bn_set_word(bn, w) gcry_mpi_set_ui(bn, w)
|
||||
#define bn_cmp(a, b) gcry_mpi_cmp(a, b)
|
||||
#define bn_copy(to, from) gcry_mpi_set(to, from)
|
||||
#define bn_sub_word(bn, w) gcry_mpi_sub_ui(bn, bn, w)
|
||||
#define bn_cmp_1(bn) gcry_mpi_cmp_ui(bn, 1)
|
||||
#define bn_num_bytes(bn) (gcry_mpi_get_nbits(bn) + 7) / 8
|
||||
#define bn_bn2bin(bn, buf, len) gcry_mpi_print(GCRYMPI_FMT_USG, buf, len, NULL, bn)
|
||||
#define bn_bin2bn(bn, buf, len) gcry_mpi_scan(&bn, GCRYMPI_FMT_USG, buf, len, NULL)
|
||||
#define bn_hex2bn(bn, buf, ret) ret = (gcry_mpi_scan(&bn, GCRYMPI_FMT_HEX, buf, 0, 0) == 0)
|
||||
#define bn_modexp(bn, y, q, p) gcry_mpi_powm(bn, y, q, p)
|
||||
#define bn_random(bn, num_bytes) gcry_mpi_randomize(bn, num_bytes, GCRY_WEAK_RANDOM)
|
||||
#endif
|
||||
|
||||
#define MAX_BYTES 18000
|
||||
|
||||
#define dh_new() av_malloc(sizeof(FF_DH))
|
||||
|
||||
static FFBigNum dh_generate_key(FF_DH *dh)
|
||||
{
|
||||
int num_bytes;
|
||||
|
||||
num_bytes = bn_num_bytes(dh->p) - 1;
|
||||
if (num_bytes <= 0 || num_bytes > MAX_BYTES)
|
||||
return NULL;
|
||||
|
||||
bn_new(dh->priv_key);
|
||||
if (!dh->priv_key)
|
||||
return NULL;
|
||||
bn_random(dh->priv_key, num_bytes);
|
||||
|
||||
bn_new(dh->pub_key);
|
||||
if (!dh->pub_key) {
|
||||
bn_free(dh->priv_key);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bn_modexp(dh->pub_key, dh->g, dh->priv_key, dh->p);
|
||||
|
||||
return dh->pub_key;
|
||||
}
|
||||
|
||||
static int dh_compute_key(FF_DH *dh, FFBigNum pub_key_bn,
|
||||
uint32_t pub_key_len, uint8_t *secret_key)
|
||||
{
|
||||
FFBigNum k;
|
||||
int num_bytes;
|
||||
|
||||
num_bytes = bn_num_bytes(dh->p);
|
||||
if (num_bytes <= 0 || num_bytes > MAX_BYTES)
|
||||
return -1;
|
||||
|
||||
bn_new(k);
|
||||
if (!k)
|
||||
return -1;
|
||||
|
||||
bn_modexp(k, pub_key_bn, dh->priv_key, dh->p);
|
||||
bn_bn2bin(k, secret_key, pub_key_len);
|
||||
bn_free(k);
|
||||
|
||||
/* return the length of the shared secret key like DH_compute_key */
|
||||
return pub_key_len;
|
||||
}
|
||||
|
||||
void ff_dh_free(FF_DH *dh)
|
||||
{
|
||||
bn_free(dh->p);
|
||||
bn_free(dh->g);
|
||||
bn_free(dh->pub_key);
|
||||
bn_free(dh->priv_key);
|
||||
av_free(dh);
|
||||
}
|
||||
#elif CONFIG_OPENSSL
|
||||
#define bn_new(bn) bn = BN_new()
|
||||
#define bn_free(bn) BN_free(bn)
|
||||
#define bn_set_word(bn, w) BN_set_word(bn, w)
|
||||
#define bn_cmp(a, b) BN_cmp(a, b)
|
||||
#define bn_copy(to, from) BN_copy(to, from)
|
||||
#define bn_sub_word(bn, w) BN_sub_word(bn, w)
|
||||
#define bn_cmp_1(bn) BN_cmp(bn, BN_value_one())
|
||||
#define bn_num_bytes(bn) BN_num_bytes(bn)
|
||||
#define bn_bn2bin(bn, buf, len) BN_bn2bin(bn, buf)
|
||||
#define bn_bin2bn(bn, buf, len) bn = BN_bin2bn(buf, len, 0)
|
||||
#define bn_hex2bn(bn, buf, ret) ret = BN_hex2bn(&bn, buf)
|
||||
#define bn_modexp(bn, y, q, p) \
|
||||
do { \
|
||||
BN_CTX *ctx = BN_CTX_new(); \
|
||||
if (!ctx) \
|
||||
return AVERROR(ENOMEM); \
|
||||
if (!BN_mod_exp(bn, y, q, p, ctx)) { \
|
||||
BN_CTX_free(ctx); \
|
||||
return AVERROR(EINVAL); \
|
||||
} \
|
||||
BN_CTX_free(ctx); \
|
||||
} while (0)
|
||||
|
||||
#define dh_new() DH_new()
|
||||
#define dh_generate_key(dh) DH_generate_key(dh)
|
||||
#define dh_compute_key(dh, pub, len, secret) DH_compute_key(secret, pub, dh)
|
||||
|
||||
void ff_dh_free(FF_DH *dh)
|
||||
{
|
||||
DH_free(dh);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int dh_is_valid_public_key(FFBigNum y, FFBigNum p, FFBigNum q)
|
||||
{
|
||||
FFBigNum bn = NULL;
|
||||
int ret = AVERROR(EINVAL);
|
||||
|
||||
bn_new(bn);
|
||||
if (!bn)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
/* y must lie in [2, p - 1] */
|
||||
bn_set_word(bn, 1);
|
||||
if (!bn_cmp(y, bn))
|
||||
goto fail;
|
||||
|
||||
/* bn = p - 2 */
|
||||
bn_copy(bn, p);
|
||||
bn_sub_word(bn, 1);
|
||||
if (!bn_cmp(y, bn))
|
||||
goto fail;
|
||||
|
||||
/* Verify with Sophie-Germain prime
|
||||
*
|
||||
* This is a nice test to make sure the public key position is calculated
|
||||
* correctly. This test will fail in about 50% of the cases if applied to
|
||||
* random data.
|
||||
*/
|
||||
/* y must fulfill y^q mod p = 1 */
|
||||
bn_modexp(bn, y, q, p);
|
||||
|
||||
if (bn_cmp_1(bn))
|
||||
goto fail;
|
||||
|
||||
ret = 0;
|
||||
fail:
|
||||
bn_free(bn);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
av_cold FF_DH *ff_dh_init(int key_len)
|
||||
{
|
||||
FF_DH *dh;
|
||||
int ret;
|
||||
|
||||
if (!(dh = dh_new()))
|
||||
return NULL;
|
||||
|
||||
bn_new(dh->g);
|
||||
if (!dh->g)
|
||||
goto fail;
|
||||
|
||||
bn_hex2bn(dh->p, P1024, ret);
|
||||
if (!ret)
|
||||
goto fail;
|
||||
|
||||
bn_set_word(dh->g, 2);
|
||||
dh->length = key_len;
|
||||
|
||||
return dh;
|
||||
|
||||
fail:
|
||||
ff_dh_free(dh);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int ff_dh_generate_public_key(FF_DH *dh)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
while (!ret) {
|
||||
FFBigNum q1 = NULL;
|
||||
|
||||
if (!dh_generate_key(dh))
|
||||
return AVERROR(EINVAL);
|
||||
|
||||
bn_hex2bn(q1, Q1024, ret);
|
||||
if (!ret)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
ret = dh_is_valid_public_key(dh->pub_key, dh->p, q1);
|
||||
bn_free(q1);
|
||||
|
||||
if (!ret) {
|
||||
/* the public key is valid */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ff_dh_write_public_key(FF_DH *dh, uint8_t *pub_key, int pub_key_len)
|
||||
{
|
||||
int len;
|
||||
|
||||
/* compute the length of the public key */
|
||||
len = bn_num_bytes(dh->pub_key);
|
||||
if (len <= 0 || len > pub_key_len)
|
||||
return AVERROR(EINVAL);
|
||||
|
||||
/* convert the public key value into big-endian form */
|
||||
memset(pub_key, 0, pub_key_len);
|
||||
bn_bn2bin(dh->pub_key, pub_key + pub_key_len - len, len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ff_dh_compute_shared_secret_key(FF_DH *dh, const uint8_t *pub_key,
|
||||
int pub_key_len, uint8_t *secret_key)
|
||||
{
|
||||
FFBigNum q1 = NULL, pub_key_bn = NULL;
|
||||
int ret;
|
||||
|
||||
/* convert the big-endian form of the public key into a bignum */
|
||||
bn_bin2bn(pub_key_bn, pub_key, pub_key_len);
|
||||
if (!pub_key_bn)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
/* convert the string containing a hexadecimal number into a bignum */
|
||||
bn_hex2bn(q1, Q1024, ret);
|
||||
if (!ret) {
|
||||
ret = AVERROR(ENOMEM);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* when the public key is valid we have to compute the shared secret key */
|
||||
if ((ret = dh_is_valid_public_key(pub_key_bn, dh->p, q1)) < 0) {
|
||||
goto fail;
|
||||
} else if ((ret = dh_compute_key(dh, pub_key_bn, pub_key_len,
|
||||
secret_key)) < 0) {
|
||||
ret = AVERROR(EINVAL);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
fail:
|
||||
bn_free(pub_key_bn);
|
||||
bn_free(q1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
102
libavformat/rtmpdh.h
Normal file
102
libavformat/rtmpdh.h
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* RTMP Diffie-Hellmann utilities
|
||||
* Copyright (c) 2012 Samuel Pitoiset
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef AVFORMAT_RTMPDH_H
|
||||
#define AVFORMAT_RTMPDH_H
|
||||
|
||||
#include "avformat.h"
|
||||
#include "config.h"
|
||||
|
||||
#if CONFIG_NETTLE || CONFIG_GCRYPT
|
||||
#if CONFIG_NETTLE
|
||||
#include <gmp.h>
|
||||
#include <nettle/bignum.h>
|
||||
|
||||
typedef mpz_ptr FFBigNum;
|
||||
#elif CONFIG_GCRYPT
|
||||
#include <gcrypt.h>
|
||||
|
||||
typedef gcry_mpi_t FFBigNum;
|
||||
#endif
|
||||
|
||||
typedef struct FF_DH {
|
||||
FFBigNum p;
|
||||
FFBigNum g;
|
||||
FFBigNum pub_key;
|
||||
FFBigNum priv_key;
|
||||
long length;
|
||||
} FF_DH;
|
||||
|
||||
#elif CONFIG_OPENSSL
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/dh.h>
|
||||
|
||||
typedef BIGNUM *FFBigNum;
|
||||
typedef DH FF_DH;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Initialize a Diffie-Hellmann context.
|
||||
*
|
||||
* @param key_len length of the key
|
||||
* @return a new Diffie-Hellmann context on success, NULL otherwise
|
||||
*/
|
||||
FF_DH *ff_dh_init(int key_len);
|
||||
|
||||
/**
|
||||
* Free a Diffie-Hellmann context.
|
||||
*
|
||||
* @param dh a Diffie-Hellmann context to free
|
||||
*/
|
||||
void ff_dh_free(FF_DH *dh);
|
||||
|
||||
/**
|
||||
* Generate a public key.
|
||||
*
|
||||
* @param dh a Diffie-Hellmann context
|
||||
* @return zero on success, negative value otherwise
|
||||
*/
|
||||
int ff_dh_generate_public_key(FF_DH *dh);
|
||||
|
||||
/**
|
||||
* Write the public key into the given buffer.
|
||||
*
|
||||
* @param dh a Diffie-Hellmann context, containing the public key to write
|
||||
* @param pub_key the buffer where the public key is written
|
||||
* @param pub_key_len the length of the buffer
|
||||
* @return zero on success, negative value otherwise
|
||||
*/
|
||||
int ff_dh_write_public_key(FF_DH *dh, uint8_t *pub_key, int pub_key_len);
|
||||
|
||||
/**
|
||||
* Compute the shared secret key from the private FF_DH value and the
|
||||
* other party's public value.
|
||||
*
|
||||
* @param dh a Diffie-Hellmann context, containing the private key
|
||||
* @param pub_key the buffer containing the public key
|
||||
* @param pub_key_len the length of the buffer
|
||||
* @param secret_key the buffer where the secret key is written
|
||||
* @return length of the shared secret key on success, negative value otherwise
|
||||
*/
|
||||
int ff_dh_compute_shared_secret_key(FF_DH *dh, const uint8_t *pub_key,
|
||||
int pub_key_len, uint8_t *secret_key);
|
||||
|
||||
#endif /* AVFORMAT_RTMPDH_H */
|
@ -37,6 +37,7 @@
|
||||
|
||||
#include "flv.h"
|
||||
#include "rtmp.h"
|
||||
#include "rtmpcrypt.h"
|
||||
#include "rtmppkt.h"
|
||||
#include "url.h"
|
||||
|
||||
@ -92,6 +93,7 @@ typedef struct RTMPContext {
|
||||
int server_bw; ///< server bandwidth
|
||||
int client_buffer_time; ///< client buffer time in ms
|
||||
int flush_interval; ///< number of packets flushed in the same request (RTMPT only)
|
||||
int encrypted; ///< use an encrypted connection (RTMPE only)
|
||||
} RTMPContext;
|
||||
|
||||
#define PLAYER_KEY_OPEN_PART_LEN 30 ///< length of partial key used for first client digest signing
|
||||
@ -590,23 +592,8 @@ static int gen_bytes_read(URLContext *s, RTMPContext *rt, uint32_t ts)
|
||||
return ret;
|
||||
}
|
||||
|
||||
//TODO: Move HMAC code somewhere. Eventually.
|
||||
#define HMAC_IPAD_VAL 0x36
|
||||
#define HMAC_OPAD_VAL 0x5C
|
||||
|
||||
/**
|
||||
* Calculate HMAC-SHA2 digest for RTMP handshake packets.
|
||||
*
|
||||
* @param src input buffer
|
||||
* @param len input buffer length (should be 1536)
|
||||
* @param gap offset in buffer where 32 bytes should not be taken into account
|
||||
* when calculating digest (since it will be used to store that digest)
|
||||
* @param key digest key
|
||||
* @param keylen digest key length
|
||||
* @param dst buffer where calculated digest will be stored (32 bytes)
|
||||
*/
|
||||
static int rtmp_calc_digest(const uint8_t *src, int len, int gap,
|
||||
const uint8_t *key, int keylen, uint8_t *dst)
|
||||
int ff_rtmp_calc_digest(const uint8_t *src, int len, int gap,
|
||||
const uint8_t *key, int keylen, uint8_t *dst)
|
||||
{
|
||||
struct AVSHA *sha;
|
||||
uint8_t hmac_buf[64+32] = {0};
|
||||
@ -647,25 +634,38 @@ static int rtmp_calc_digest(const uint8_t *src, int len, int gap,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ff_rtmp_calc_digest_pos(const uint8_t *buf, int off, int mod_val,
|
||||
int add_val)
|
||||
{
|
||||
int i, digest_pos = 0;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
digest_pos += buf[i + off];
|
||||
digest_pos = digest_pos % mod_val + add_val;
|
||||
|
||||
return digest_pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put HMAC-SHA2 digest of packet data (except for the bytes where this digest
|
||||
* will be stored) into that packet.
|
||||
*
|
||||
* @param buf handshake data (1536 bytes)
|
||||
* @param encrypted use an encrypted connection (RTMPE)
|
||||
* @return offset to the digest inside input data
|
||||
*/
|
||||
static int rtmp_handshake_imprint_with_digest(uint8_t *buf)
|
||||
static int rtmp_handshake_imprint_with_digest(uint8_t *buf, int encrypted)
|
||||
{
|
||||
int i, digest_pos = 0;
|
||||
int ret;
|
||||
int ret, digest_pos;
|
||||
|
||||
for (i = 8; i < 12; i++)
|
||||
digest_pos += buf[i];
|
||||
digest_pos = (digest_pos % 728) + 12;
|
||||
if (encrypted)
|
||||
digest_pos = ff_rtmp_calc_digest_pos(buf, 772, 728, 776);
|
||||
else
|
||||
digest_pos = ff_rtmp_calc_digest_pos(buf, 8, 728, 12);
|
||||
|
||||
ret = rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
|
||||
rtmp_player_key, PLAYER_KEY_OPEN_PART_LEN,
|
||||
buf + digest_pos);
|
||||
ret = ff_rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
|
||||
rtmp_player_key, PLAYER_KEY_OPEN_PART_LEN,
|
||||
buf + digest_pos);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@ -681,17 +681,14 @@ static int rtmp_handshake_imprint_with_digest(uint8_t *buf)
|
||||
*/
|
||||
static int rtmp_validate_digest(uint8_t *buf, int off)
|
||||
{
|
||||
int i, digest_pos = 0;
|
||||
uint8_t digest[32];
|
||||
int ret;
|
||||
int ret, digest_pos;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
digest_pos += buf[i + off];
|
||||
digest_pos = (digest_pos % 728) + off + 4;
|
||||
digest_pos = ff_rtmp_calc_digest_pos(buf, off, 728, off + 4);
|
||||
|
||||
ret = rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
|
||||
rtmp_server_key, SERVER_KEY_OPEN_PART_LEN,
|
||||
digest);
|
||||
ret = ff_rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
|
||||
rtmp_server_key, SERVER_KEY_OPEN_PART_LEN,
|
||||
digest);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@ -721,8 +718,9 @@ static int rtmp_handshake(URLContext *s, RTMPContext *rt)
|
||||
uint8_t serverdata[RTMP_HANDSHAKE_PACKET_SIZE+1];
|
||||
int i;
|
||||
int server_pos, client_pos;
|
||||
uint8_t digest[32];
|
||||
int ret;
|
||||
uint8_t digest[32], signature[32];
|
||||
int encrypted = rt->encrypted && CONFIG_FFRTMPCRYPT_PROTOCOL;
|
||||
int ret, type = 0;
|
||||
|
||||
av_log(s, AV_LOG_DEBUG, "Handshaking...\n");
|
||||
|
||||
@ -730,7 +728,24 @@ static int rtmp_handshake(URLContext *s, RTMPContext *rt)
|
||||
// generate handshake packet - 1536 bytes of pseudorandom data
|
||||
for (i = 9; i <= RTMP_HANDSHAKE_PACKET_SIZE; i++)
|
||||
tosend[i] = av_lfg_get(&rnd) >> 24;
|
||||
client_pos = rtmp_handshake_imprint_with_digest(tosend + 1);
|
||||
|
||||
if (encrypted) {
|
||||
/* When the client wants to use RTMPE, we have to change the command
|
||||
* byte to 0x06 which means to use encrypted data and we have to set
|
||||
* the flash version to at least 9.0.115.0. */
|
||||
tosend[0] = 6;
|
||||
tosend[5] = 128;
|
||||
tosend[6] = 0;
|
||||
tosend[7] = 3;
|
||||
tosend[8] = 2;
|
||||
|
||||
/* Initialize the Diffie-Hellmann context and generate the public key
|
||||
* to send to the server. */
|
||||
if ((ret = ff_rtmpe_gen_pub_key(rt->stream, tosend + 1)) < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
client_pos = rtmp_handshake_imprint_with_digest(tosend + 1, encrypted);
|
||||
if (client_pos < 0)
|
||||
return client_pos;
|
||||
|
||||
@ -752,6 +767,7 @@ static int rtmp_handshake(URLContext *s, RTMPContext *rt)
|
||||
return ret;
|
||||
}
|
||||
|
||||
av_log(s, AV_LOG_DEBUG, "Type answer %d\n", serverdata[0]);
|
||||
av_log(s, AV_LOG_DEBUG, "Server version %d.%d.%d.%d\n",
|
||||
serverdata[5], serverdata[6], serverdata[7], serverdata[8]);
|
||||
|
||||
@ -761,6 +777,7 @@ static int rtmp_handshake(URLContext *s, RTMPContext *rt)
|
||||
return server_pos;
|
||||
|
||||
if (!server_pos) {
|
||||
type = 1;
|
||||
server_pos = rtmp_validate_digest(serverdata + 1, 8);
|
||||
if (server_pos < 0)
|
||||
return server_pos;
|
||||
@ -771,43 +788,88 @@ static int rtmp_handshake(URLContext *s, RTMPContext *rt)
|
||||
}
|
||||
}
|
||||
|
||||
ret = rtmp_calc_digest(tosend + 1 + client_pos, 32, 0, rtmp_server_key,
|
||||
sizeof(rtmp_server_key), digest);
|
||||
ret = ff_rtmp_calc_digest(tosend + 1 + client_pos, 32, 0,
|
||||
rtmp_server_key, sizeof(rtmp_server_key),
|
||||
digest);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = rtmp_calc_digest(clientdata, RTMP_HANDSHAKE_PACKET_SIZE - 32, 0,
|
||||
digest, 32, digest);
|
||||
ret = ff_rtmp_calc_digest(clientdata, RTMP_HANDSHAKE_PACKET_SIZE - 32,
|
||||
0, digest, 32, signature);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (memcmp(digest, clientdata + RTMP_HANDSHAKE_PACKET_SIZE - 32, 32)) {
|
||||
if (encrypted) {
|
||||
/* Compute the shared secret key sent by the server and initialize
|
||||
* the RC4 encryption. */
|
||||
if ((ret = ff_rtmpe_compute_secret_key(rt->stream, serverdata + 1,
|
||||
tosend + 1, type)) < 0)
|
||||
return ret;
|
||||
|
||||
/* Encrypt the signature received by the server. */
|
||||
ff_rtmpe_encrypt_sig(rt->stream, signature, digest, serverdata[0]);
|
||||
}
|
||||
|
||||
if (memcmp(signature, clientdata + RTMP_HANDSHAKE_PACKET_SIZE - 32, 32)) {
|
||||
av_log(s, AV_LOG_ERROR, "Signature mismatch\n");
|
||||
return AVERROR(EIO);
|
||||
}
|
||||
|
||||
for (i = 0; i < RTMP_HANDSHAKE_PACKET_SIZE; i++)
|
||||
tosend[i] = av_lfg_get(&rnd) >> 24;
|
||||
ret = rtmp_calc_digest(serverdata + 1 + server_pos, 32, 0,
|
||||
rtmp_player_key, sizeof(rtmp_player_key),
|
||||
digest);
|
||||
ret = ff_rtmp_calc_digest(serverdata + 1 + server_pos, 32, 0,
|
||||
rtmp_player_key, sizeof(rtmp_player_key),
|
||||
digest);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = rtmp_calc_digest(tosend, RTMP_HANDSHAKE_PACKET_SIZE - 32, 0,
|
||||
digest, 32,
|
||||
tosend + RTMP_HANDSHAKE_PACKET_SIZE - 32);
|
||||
ret = ff_rtmp_calc_digest(tosend, RTMP_HANDSHAKE_PACKET_SIZE - 32, 0,
|
||||
digest, 32,
|
||||
tosend + RTMP_HANDSHAKE_PACKET_SIZE - 32);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (encrypted) {
|
||||
/* Encrypt the signature to be send to the server. */
|
||||
ff_rtmpe_encrypt_sig(rt->stream, tosend +
|
||||
RTMP_HANDSHAKE_PACKET_SIZE - 32, digest,
|
||||
serverdata[0]);
|
||||
}
|
||||
|
||||
// write reply back to the server
|
||||
if ((ret = ffurl_write(rt->stream, tosend,
|
||||
RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
|
||||
return ret;
|
||||
|
||||
if (encrypted) {
|
||||
/* Set RC4 keys for encryption and update the keystreams. */
|
||||
if ((ret = ff_rtmpe_update_keystream(rt->stream)) < 0)
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
if (encrypted) {
|
||||
/* Compute the shared secret key sent by the server and initialize
|
||||
* the RC4 encryption. */
|
||||
if ((ret = ff_rtmpe_compute_secret_key(rt->stream, serverdata + 1,
|
||||
tosend + 1, 1)) < 0)
|
||||
return ret;
|
||||
|
||||
if (serverdata[0] == 9) {
|
||||
/* Encrypt the signature received by the server. */
|
||||
ff_rtmpe_encrypt_sig(rt->stream, signature, digest,
|
||||
serverdata[0]);
|
||||
}
|
||||
}
|
||||
|
||||
if ((ret = ffurl_write(rt->stream, serverdata + 1,
|
||||
RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
|
||||
return ret;
|
||||
|
||||
if (encrypted) {
|
||||
/* Set RC4 keys for encryption and update the keystreams. */
|
||||
if ((ret = ff_rtmpe_update_keystream(rt->stream)) < 0)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -1130,6 +1192,13 @@ static int rtmp_open(URLContext *s, const char *uri, int flags)
|
||||
if (port < 0)
|
||||
port = RTMPS_DEFAULT_PORT;
|
||||
ff_url_join(buf, sizeof(buf), "tls", NULL, hostname, port, NULL);
|
||||
} else if (!strcmp(proto, "rtmpe") || (!strcmp(proto, "rtmpte"))) {
|
||||
if (!strcmp(proto, "rtmpte"))
|
||||
av_dict_set(&opts, "ffrtmpcrypt_tunneling", "1", 1);
|
||||
|
||||
/* open the encrypted connection */
|
||||
ff_url_join(buf, sizeof(buf), "ffrtmpcrypt", NULL, hostname, port, NULL);
|
||||
rt->encrypted = 1;
|
||||
} else {
|
||||
/* open the tcp connection */
|
||||
if (port < 0)
|
||||
@ -1454,6 +1523,24 @@ URLProtocol ff_rtmp_protocol = {
|
||||
.priv_data_class= &rtmp_class,
|
||||
};
|
||||
|
||||
static const AVClass rtmpe_class = {
|
||||
.class_name = "rtmpe",
|
||||
.item_name = av_default_item_name,
|
||||
.option = rtmp_options,
|
||||
.version = LIBAVUTIL_VERSION_INT,
|
||||
};
|
||||
|
||||
URLProtocol ff_rtmpe_protocol = {
|
||||
.name = "rtmpe",
|
||||
.url_open = rtmp_open,
|
||||
.url_read = rtmp_read,
|
||||
.url_write = rtmp_write,
|
||||
.url_close = rtmp_close,
|
||||
.priv_data_size = sizeof(RTMPContext),
|
||||
.flags = URL_PROTOCOL_FLAG_NETWORK,
|
||||
.priv_data_class = &rtmpe_class,
|
||||
};
|
||||
|
||||
static const AVClass rtmps_class = {
|
||||
.class_name = "rtmps",
|
||||
.item_name = av_default_item_name,
|
||||
@ -1490,6 +1577,24 @@ URLProtocol ff_rtmpt_protocol = {
|
||||
.priv_data_class = &rtmpt_class,
|
||||
};
|
||||
|
||||
static const AVClass rtmpte_class = {
|
||||
.class_name = "rtmpte",
|
||||
.item_name = av_default_item_name,
|
||||
.option = rtmp_options,
|
||||
.version = LIBAVUTIL_VERSION_INT,
|
||||
};
|
||||
|
||||
URLProtocol ff_rtmpte_protocol = {
|
||||
.name = "rtmpte",
|
||||
.url_open = rtmp_open,
|
||||
.url_read = rtmp_read,
|
||||
.url_write = rtmp_write,
|
||||
.url_close = rtmp_close,
|
||||
.priv_data_size = sizeof(RTMPContext),
|
||||
.flags = URL_PROTOCOL_FLAG_NETWORK,
|
||||
.priv_data_class = &rtmpte_class,
|
||||
};
|
||||
|
||||
static const AVClass rtmpts_class = {
|
||||
.class_name = "rtmpts",
|
||||
.item_name = av_default_item_name,
|
||||
|
@ -30,7 +30,7 @@
|
||||
#include "libavutil/avutil.h"
|
||||
|
||||
#define LIBAVFORMAT_VERSION_MAJOR 54
|
||||
#define LIBAVFORMAT_VERSION_MINOR 19
|
||||
#define LIBAVFORMAT_VERSION_MINOR 20
|
||||
#define LIBAVFORMAT_VERSION_MICRO 100
|
||||
|
||||
#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
|
||||
|
@ -625,3 +625,15 @@
|
||||
shufps %1, %1, 0
|
||||
%endif
|
||||
%endmacro
|
||||
|
||||
%macro SHUFFLE_MASK_W 8
|
||||
%rep 8
|
||||
%if %1>=0x80
|
||||
db %1, %1
|
||||
%else
|
||||
db %1*2
|
||||
db %1*2+1
|
||||
%endif
|
||||
%rotate 1
|
||||
%endrep
|
||||
%endmacro
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "libavutil/attributes.h"
|
||||
#include "libavutil/avutil.h"
|
||||
#include "libavutil/avassert.h"
|
||||
#include "libavutil/bswap.h"
|
||||
@ -1260,13 +1261,13 @@ YUV2RGBWRAPPERX(yuv2, rgb_full, xrgb32_full, PIX_FMT_ARGB, 0)
|
||||
YUV2RGBWRAPPERX(yuv2, rgb_full, bgr24_full, PIX_FMT_BGR24, 0)
|
||||
YUV2RGBWRAPPERX(yuv2, rgb_full, rgb24_full, PIX_FMT_RGB24, 0)
|
||||
|
||||
void ff_sws_init_output_funcs(SwsContext *c,
|
||||
yuv2planar1_fn *yuv2plane1,
|
||||
yuv2planarX_fn *yuv2planeX,
|
||||
yuv2interleavedX_fn *yuv2nv12cX,
|
||||
yuv2packed1_fn *yuv2packed1,
|
||||
yuv2packed2_fn *yuv2packed2,
|
||||
yuv2packedX_fn *yuv2packedX)
|
||||
av_cold void ff_sws_init_output_funcs(SwsContext *c,
|
||||
yuv2planar1_fn *yuv2plane1,
|
||||
yuv2planarX_fn *yuv2planeX,
|
||||
yuv2interleavedX_fn *yuv2nv12cX,
|
||||
yuv2packed1_fn *yuv2packed1,
|
||||
yuv2packed2_fn *yuv2packed2,
|
||||
yuv2packedX_fn *yuv2packedX)
|
||||
{
|
||||
enum PixelFormat dstFormat = c->dstFormat;
|
||||
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "config.h"
|
||||
#include "libswscale/swscale.h"
|
||||
#include "libswscale/swscale_internal.h"
|
||||
#include "libavutil/attributes.h"
|
||||
#include "libavutil/cpu.h"
|
||||
#include "yuv2rgb_altivec.h"
|
||||
|
||||
@ -310,7 +311,7 @@ static void hScale_altivec_real(SwsContext *c, int16_t *dst, int dstW,
|
||||
}
|
||||
}
|
||||
|
||||
void ff_sws_init_swScale_altivec(SwsContext *c)
|
||||
av_cold void ff_sws_init_swScale_altivec(SwsContext *c)
|
||||
{
|
||||
enum PixelFormat dstFormat = c->dstFormat;
|
||||
|
||||
|
@ -95,6 +95,7 @@
|
||||
#include "libswscale/rgb2rgb.h"
|
||||
#include "libswscale/swscale.h"
|
||||
#include "libswscale/swscale_internal.h"
|
||||
#include "libavutil/attributes.h"
|
||||
#include "libavutil/cpu.h"
|
||||
#include "libavutil/pixdesc.h"
|
||||
#include "yuv2rgb_altivec.h"
|
||||
@ -531,7 +532,7 @@ static int altivec_uyvy_rgb32(SwsContext *c, const unsigned char **in,
|
||||
*
|
||||
* So we just fall back to the C codes for this.
|
||||
*/
|
||||
SwsFunc ff_yuv2rgb_init_altivec(SwsContext *c)
|
||||
av_cold SwsFunc ff_yuv2rgb_init_altivec(SwsContext *c)
|
||||
{
|
||||
if (!(av_get_cpu_flags() & AV_CPU_FLAG_ALTIVEC))
|
||||
return NULL;
|
||||
@ -591,9 +592,11 @@ SwsFunc ff_yuv2rgb_init_altivec(SwsContext *c)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ff_yuv2rgb_init_tables_altivec(SwsContext *c, const int inv_table[4],
|
||||
int brightness, int contrast,
|
||||
int saturation)
|
||||
av_cold void ff_yuv2rgb_init_tables_altivec(SwsContext *c,
|
||||
const int inv_table[4],
|
||||
int brightness,
|
||||
int contrast,
|
||||
int saturation)
|
||||
{
|
||||
union {
|
||||
DECLARE_ALIGNED(16, signed short, tmp)[8];
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "libavutil/attributes.h"
|
||||
#include "libavutil/bswap.h"
|
||||
#include "config.h"
|
||||
#include "rgb2rgb.h"
|
||||
@ -125,7 +126,7 @@ void (*yuyvtoyuv422)(uint8_t *ydst, uint8_t *udst, uint8_t *vdst,
|
||||
* 32-bit C version, and and&add trick by Michael Niedermayer
|
||||
*/
|
||||
|
||||
void sws_rgb2rgb_init(void)
|
||||
av_cold void sws_rgb2rgb_init(void)
|
||||
{
|
||||
rgb2rgb_init_c();
|
||||
if (HAVE_MMX)
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "libavutil/attributes.h"
|
||||
#include "libswscale/swscale.h"
|
||||
#include "libswscale/swscale_internal.h"
|
||||
|
||||
@ -184,7 +185,7 @@ static int vis_422P_ARGB32(SwsContext *c, uint8_t *src[], int srcStride[],
|
||||
return srcSliceH;
|
||||
}
|
||||
|
||||
SwsFunc ff_yuv2rgb_init_vis(SwsContext *c)
|
||||
av_cold SwsFunc ff_yuv2rgb_init_vis(SwsContext *c)
|
||||
{
|
||||
c->sparc_coeffs[5] = c->yCoeff;
|
||||
c->sparc_coeffs[6] = c->vgCoeff;
|
||||
|
@ -544,7 +544,7 @@ static int swScale(SwsContext *c, const uint8_t *src[],
|
||||
if (!enough_lines)
|
||||
break; // we can't output a dstY line so let's try with the next slice
|
||||
|
||||
#if HAVE_MMX
|
||||
#if HAVE_MMX && HAVE_INLINE_ASM
|
||||
updateMMXDitherTables(c, dstY, lumBufIndex, chrBufIndex,
|
||||
lastInLumBuf, lastInChrBuf);
|
||||
#endif
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "libavutil/attributes.h"
|
||||
#include "libavutil/avassert.h"
|
||||
#include "libavutil/avutil.h"
|
||||
#include "libavutil/bswap.h"
|
||||
@ -598,7 +599,7 @@ fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if HAVE_MMX2
|
||||
#if HAVE_MMX2 && HAVE_INLINE_ASM
|
||||
static int initMMX2HScaler(int dstW, int xInc, uint8_t *filterCode,
|
||||
int16_t *filter, int32_t *filterPos, int numSplits)
|
||||
{
|
||||
@ -761,7 +762,7 @@ static int initMMX2HScaler(int dstW, int xInc, uint8_t *filterCode,
|
||||
|
||||
return fragmentPos + 1;
|
||||
}
|
||||
#endif /* HAVE_MMX2 */
|
||||
#endif /* HAVE_MMX2 && HAVE_INLINE_ASM */
|
||||
|
||||
static void getSubSampleFactors(int *h, int *v, enum PixelFormat format)
|
||||
{
|
||||
@ -856,7 +857,8 @@ SwsContext *sws_alloc_context(void)
|
||||
return c;
|
||||
}
|
||||
|
||||
int sws_init_context(SwsContext *c, SwsFilter *srcFilter, SwsFilter *dstFilter)
|
||||
av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter,
|
||||
SwsFilter *dstFilter)
|
||||
{
|
||||
int i, j;
|
||||
int usesVFilter, usesHFilter;
|
||||
@ -1022,7 +1024,7 @@ int sws_init_context(SwsContext *c, SwsFilter *srcFilter, SwsFilter *dstFilter)
|
||||
c->srcBpc = 16;
|
||||
if (c->dstBpc == 16)
|
||||
dst_stride <<= 1;
|
||||
if (HAVE_MMX2 && cpu_flags & AV_CPU_FLAG_MMX2 &&
|
||||
if (HAVE_MMX2 && HAVE_INLINE_ASM && cpu_flags & AV_CPU_FLAG_MMX2 &&
|
||||
c->srcBpc == 8 && c->dstBpc <= 14) {
|
||||
c->canMMX2BeUsed = (dstW >= srcW && (dstW & 31) == 0 &&
|
||||
(srcW & 15) == 0) ? 1 : 0;
|
||||
@ -1061,7 +1063,7 @@ int sws_init_context(SwsContext *c, SwsFilter *srcFilter, SwsFilter *dstFilter)
|
||||
|
||||
/* precalculate horizontal scaler filter coefficients */
|
||||
{
|
||||
#if HAVE_MMX2
|
||||
#if HAVE_MMX2 && HAVE_INLINE_ASM
|
||||
// can't downscale !!!
|
||||
if (c->canMMX2BeUsed && (flags & SWS_FAST_BILINEAR)) {
|
||||
c->lumMmx2FilterCodeSize = initMMX2HScaler(dstW, c->lumXInc, NULL,
|
||||
@ -1105,7 +1107,7 @@ int sws_init_context(SwsContext *c, SwsFilter *srcFilter, SwsFilter *dstFilter)
|
||||
mprotect(c->chrMmx2FilterCode, c->chrMmx2FilterCodeSize, PROT_EXEC | PROT_READ);
|
||||
#endif
|
||||
} else
|
||||
#endif /* HAVE_MMX2 */
|
||||
#endif /* HAVE_MMX2 && HAVE_INLINE_ASM */
|
||||
{
|
||||
const int filterAlign =
|
||||
(HAVE_MMX && cpu_flags & AV_CPU_FLAG_MMX) ? 4 :
|
||||
|
@ -3,8 +3,8 @@ $(SUBDIR)x86/swscale_mmx.o: CFLAGS += $(NOREDZONE_FLAGS)
|
||||
OBJS-$(CONFIG_XMM_CLOBBER_TEST) += x86/w64xmmtest.o
|
||||
|
||||
MMX-OBJS += x86/rgb2rgb.o \
|
||||
x86/swscale_mmx.o \
|
||||
x86/yuv2rgb_mmx.o \
|
||||
x86/swscale.o \
|
||||
x86/yuv2rgb.o \
|
||||
|
||||
YASM-OBJS += x86/input.o \
|
||||
x86/output.o \
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "libavutil/attributes.h"
|
||||
#include "libavutil/x86_cpu.h"
|
||||
#include "libavutil/cpu.h"
|
||||
#include "libavutil/bswap.h"
|
||||
@ -130,7 +131,7 @@ DECLARE_ASM_CONST(8, uint64_t, mul16_mid) = 0x2080208020802080ULL;
|
||||
|
||||
#endif /* HAVE_INLINE_ASM */
|
||||
|
||||
void rgb2rgb_init_x86(void)
|
||||
av_cold void rgb2rgb_init_x86(void)
|
||||
{
|
||||
#if HAVE_INLINE_ASM
|
||||
int cpu_flags = av_get_cpu_flags();
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "config.h"
|
||||
#include "libswscale/swscale.h"
|
||||
#include "libswscale/swscale_internal.h"
|
||||
#include "libavutil/attributes.h"
|
||||
#include "libavutil/avassert.h"
|
||||
#include "libavutil/intreadwrite.h"
|
||||
#include "libavutil/x86_cpu.h"
|
||||
@ -367,7 +368,7 @@ INPUT_FUNCS(sse2);
|
||||
INPUT_FUNCS(ssse3);
|
||||
INPUT_FUNCS(avx);
|
||||
|
||||
void ff_sws_init_swScale_mmx(SwsContext *c)
|
||||
av_cold void ff_sws_init_swScale_mmx(SwsContext *c)
|
||||
{
|
||||
int cpu_flags = av_get_cpu_flags();
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "libswscale/rgb2rgb.h"
|
||||
#include "libswscale/swscale.h"
|
||||
#include "libswscale/swscale_internal.h"
|
||||
#include "libavutil/attributes.h"
|
||||
#include "libavutil/x86_cpu.h"
|
||||
#include "libavutil/cpu.h"
|
||||
|
||||
@ -68,7 +69,7 @@ DECLARE_ASM_CONST(8, uint64_t, pb_07) = 0x0707070707070707ULL;
|
||||
|
||||
#endif /* HAVE_INLINE_ASM */
|
||||
|
||||
SwsFunc ff_yuv2rgb_init_mmx(SwsContext *c)
|
||||
av_cold SwsFunc ff_yuv2rgb_init_mmx(SwsContext *c)
|
||||
{
|
||||
#if HAVE_INLINE_ASM
|
||||
int cpu_flags = av_get_cpu_flags();
|
@ -36,6 +36,9 @@ fate-vc1_sa10091: CMD = framecrc -i $(SAMPLES)/vc1/SA10091.vc1
|
||||
FATE_VC1 += fate-vc1_sa20021
|
||||
fate-vc1_sa20021: CMD = framecrc -i $(SAMPLES)/vc1/SA20021.vc1
|
||||
|
||||
#FATE_VC1 += fate-vc1_sa10143
|
||||
fate-vc1_sa10143: CMD = framecrc -i $(SAMPLES)/vc1/SA10143.vc1
|
||||
|
||||
FATE_VC1 += fate-vc1-ism
|
||||
fate-vc1-ism: CMD = framecrc -i $(SAMPLES)/isom/vc1-wmapro.ism -an
|
||||
|
||||
|
31
tests/ref/fate/vc1_sa10143
Normal file
31
tests/ref/fate/vc1_sa10143
Normal file
@ -0,0 +1,31 @@
|
||||
#tb 0: 1/25
|
||||
0, 0, 0, 1, 518400, 0x89407f55
|
||||
0, 2, 2, 1, 518400, 0xeb8d84a1
|
||||
0, 3, 3, 1, 518400, 0x2121ff57
|
||||
0, 4, 4, 1, 518400, 0xd81adb3d
|
||||
0, 5, 5, 1, 518400, 0x01e36aa2
|
||||
0, 6, 6, 1, 518400, 0x6b802361
|
||||
0, 7, 7, 1, 518400, 0xc8403c77
|
||||
0, 8, 8, 1, 518400, 0xdd342b5d
|
||||
0, 9, 9, 1, 518400, 0x2100eea5
|
||||
0, 10, 10, 1, 518400, 0x92a22da6
|
||||
0, 11, 11, 1, 518400, 0x6bacdef7
|
||||
0, 12, 12, 1, 518400, 0x4a00715f
|
||||
0, 13, 13, 1, 518400, 0x59b98727
|
||||
0, 14, 14, 1, 518400, 0xbf912ee1
|
||||
0, 15, 15, 1, 518400, 0x8c966cd6
|
||||
0, 16, 16, 1, 518400, 0x2c9a2535
|
||||
0, 17, 17, 1, 518400, 0x29085c06
|
||||
0, 18, 18, 1, 518400, 0x46ae6b7d
|
||||
0, 19, 19, 1, 518400, 0x283100f4
|
||||
0, 20, 20, 1, 518400, 0x2731b5ff
|
||||
0, 21, 21, 1, 518400, 0x1132ea54
|
||||
0, 22, 22, 1, 518400, 0x37cbe539
|
||||
0, 23, 23, 1, 518400, 0x08ff75cf
|
||||
0, 24, 24, 1, 518400, 0xafb6bc45
|
||||
0, 25, 25, 1, 518400, 0x19d3873d
|
||||
0, 26, 26, 1, 518400, 0xd494a8be
|
||||
0, 27, 27, 1, 518400, 0x285f41ef
|
||||
0, 28, 28, 1, 518400, 0xd4b1ffa1
|
||||
0, 29, 29, 1, 518400, 0xc3876c3a
|
||||
0, 30, 30, 1, 518400, 0xb73dbb62
|
Loading…
Reference in New Issue
Block a user