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>
pull/28/head
Michael Niedermayer 13 years ago
commit 2cb4d51654
  1. 17
      Changelog
  2. 24
      configure
  3. 4
      doc/general.texi
  4. 17
      doc/protocols.texi
  5. 42
      libavcodec/h264.c
  6. 126
      libavcodec/ppc/fmtconvert_altivec.c
  7. 7
      libavcodec/v410dec.c
  8. 2
      libavcodec/x86/dsputil_yasm.asm
  9. 2
      libavcodec/zerocodec.c
  10. 6
      libavfilter/x86/gradfun.c
  11. 6
      libavfilter/x86/yadif.c
  12. 3
      libavformat/Makefile
  13. 3
      libavformat/allformats.c
  14. 6
      libavformat/avienc.c
  15. 6
      libavformat/flvenc.c
  16. 21
      libavformat/matroskaenc.c
  17. 21
      libavformat/movenc.c
  18. 9
      libavformat/nutenc.c
  19. 28
      libavformat/rtmp.h
  20. 334
      libavformat/rtmpcrypt.c
  21. 69
      libavformat/rtmpcrypt.h
  22. 329
      libavformat/rtmpdh.c
  23. 102
      libavformat/rtmpdh.h
  24. 201
      libavformat/rtmpproto.c
  25. 2
      libavformat/version.h
  26. 12
      libavutil/x86/x86util.asm
  27. 15
      libswscale/output.c
  28. 3
      libswscale/ppc/swscale_altivec.c
  29. 11
      libswscale/ppc/yuv2rgb_altivec.c
  30. 3
      libswscale/rgb2rgb.c
  31. 3
      libswscale/sparc/yuv2rgb_vis.c
  32. 2
      libswscale/swscale.c
  33. 14
      libswscale/utils.c
  34. 4
      libswscale/x86/Makefile
  35. 3
      libswscale/x86/rgb2rgb.c
  36. 3
      libswscale/x86/swscale.c
  37. 3
      libswscale/x86/yuv2rgb.c
  38. 3
      tests/fate/microsoft.mak
  39. 31
      tests/ref/fate/vc1_sa10143

@ -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

@ -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 */

@ -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,
};

@ -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 */

@ -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;
}

@ -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

@ -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…
Cancel
Save