Index: stream/Makefile =================================================================== --- stream/Makefile (révision 22949) +++ stream/Makefile (copie de travail) @@ -18,6 +18,32 @@ SRCS_COMMON-$(FTP) += stream_ftp.c SRCS_COMMON-$(LIBSMBCLIENT) += stream_smb.c SRCS_COMMON-$(MPLAYER_NETWORK) += stream_netstream.c \ +<<<<<<< .mine + asf_mmst_streaming.c \ + asf_streaming.c \ + zattoo.c \ + cookies.c \ + http.c \ + network.c \ + pnm.c \ + rtp.c \ + udp.c \ + tcp.c \ + stream_rtp.c \ + stream_rtsp.c \ + stream_udp.c \ + freesdp/common.c \ + freesdp/errorlist.c \ + freesdp/parser.c \ + librtsp/rtsp.c \ + librtsp/rtsp_rtp.c \ + librtsp/rtsp_session.c \ + realrtsp/asmrp.c \ + realrtsp/real.c \ + realrtsp/rmff.c \ + realrtsp/sdpplin.c \ + realrtsp/xbuffer.c \ +======= asf_mmst_streaming.c \ asf_streaming.c \ cookies.c \ @@ -41,6 +67,7 @@ realrtsp/rmff.c \ realrtsp/sdpplin.c \ realrtsp/xbuffer.c \ +>>>>>>> .r22949 SRCS_COMMON-$(PVR) += stream_pvr.c SRCS_COMMON-$(RADIO) += stream_radio.c Index: stream/zattoo.c =================================================================== --- stream/zattoo.c (révision 0) +++ stream/zattoo.c (révision 0) @@ -0,0 +1,547 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "mp_msg.h" +#include "help_mp.h" + +#ifndef HAVE_WINSOCK2 +#define closesocket close +#else +#include +#endif + +#include "url.h" +#include "http.h" +#include "libmpdemux/asf.h" + +#include "stream.h" +#include "libmpdemux/demuxer.h" +#include "libmpdemux/zattoo.h" + +#include "network.h" +#include "tcp.h" + + +extern int network_bandwidth; +/*TODO: write matroska reference number*/ +/* FIXME: error propagating */ +// ignored messages: init0 and resp, side msgs to addr_server + +#define me2be_64(x) be2me_64(x) +#define me2be_32(x) be2me_32(x) +#define me2be_16(x) be2me_16(x) + +#define LTICKET_USERIDOFFSET 4 +#define INIT1_LTICKETOFFSET 33 + +uint8_t addr_server[4]={81,221,34,6}; +uint8_t log_server[4]={81,221,34,5}; + +/*struct init1 +{ + //40 + uint32_t msg_num2;//nimp + uint32_t msg_num3;//nimp + //48 + uint8_t magick2[16];//fail, nimp + //64 + uint8_t sth4[4];//nimp + uint8_t magick3[5];//ok +} __attribute__ ((packed)); +*/ + +uint8_t init1_magick[33]={ + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x0f,0x05,0x37, + 0x00,0x00,0x73,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0xff,0xff,0x39,0x36, + 0x00}; +uint8_t init2_magick2[16]={0x00,0x00,0x7a,0x12, + 0x00,0x00,0x73,0x00, + 0x00,0x00,0xf4,0x24, + 0x00,0x00,0x00,0x00}; +char addr2_magick2[8]={ + 0x00,0x00,0x73,0x00, + 0x00,0x00,0x00,0x02 +}; +/**/ +static uint8_t outmagick[2]={0x13,0x8a}; + + +struct l1_header +{ + uint8_t magick[12]; + uint32_t channel_id; + uint8_t srcip_external[4]; + uint8_t srcip_internal[4]; + uint8_t destip[4]; + uint32_t fnumber; + uint32_t user_id; + uint8_t magick2[2]; + uint16_t size; +}__attribute__ ((packed)); + + +struct addr_req2 +{ + //40 + uint32_t num2; + uint8_t sth3[8]; + uint8_t magick2[8]; + uint32_t sth4; + uint8_t sig[128]; +} __attribute__ ((packed)); +struct addr_resp2 +{ + //76=4c + uint8_t sth1[36]; + uint8_t ipanswer[4]; + uint32_t channel_id; + // uint8_t sth[16]; //is this always present? + // sometimes longer +} __attribute__ ((packed)); + +struct login_resp1 +{ + uint32_t sth1; + uint32_t user_id; + uint8_t tosig_enc[32]; +} __attribute__ ((packed)); + + +struct init2 +{ + //40 + uint32_t msg_num2;//nimp + uint32_t msg_num3;//nimp + uint8_t magick2[16];//ok +} __attribute__ ((packed)); + +struct ztv_connect +{ + uint8_t ip[4]; + uint32_t channel_id; + int fd; + char ipname[40]; +}; + +struct ztv_info +{ + RSA *myrsa; + uint8_t *lticket; + int lticketlen; + struct ztv_connect maincon; + uint32_t sendnum; +}; + + +#define DATA(x) ((struct ztv_info *)x->priv) + +static int +ztv_http_down(struct ztv_connect *connect, char *buf, int maxsize) +{ + return recv(connect->fd, buf, maxsize, 0); +} + +static int +ztv_http_send_packet(stream_t *stream, struct ztv_connect *connect, + void *inpacket, int packet_size, zattoo_msg_type_t msg_type) +{ + struct l1_header head; + char *buf; + char ipnamepad[20]; + int len; + int i; + uint8_t *packet=(uint8_t *)inpacket; + int t; + buf=malloc(sizeof(struct l1_header)+packet_size+400); + sprintf(buf, "POST http://%-15s HTTP/1.1\r\nHost: %15s\r\nContent-Length:%6d\r\n\r\n", + connect->ipname, connect->ipname, + sizeof(struct l1_header)+packet_size); + len=strlen(buf); + memset(&head,0,sizeof(head)); + memcpy(head.magick,zattoo_msg_magicks[msg_type],sizeof(head.magick)); + AV_WB32(&head.channel_id, connect->channel_id); + if(DATA(stream)->lticket) + memcpy(&head.user_id,(DATA(stream)->lticket+LTICKET_USERIDOFFSET), + sizeof(head.user_id)); + memcpy(head.destip,connect->ip,sizeof(head.destip)); + AV_WB32(&head.fnumber,DATA(stream)->sendnum); + DATA(stream)->sendnum++; + AV_WB16(&head.size,packet_size); + /* FIXME: put the real src_ip*/ + memcpy(head.srcip_external,"\x55\x00\x38\x49",sizeof(head.srcip_external)); + memcpy(head.srcip_internal,"\xc0\xa8\x01\x0f",sizeof(head.srcip_internal)); + memcpy(head.magick2,outmagick,sizeof(head.magick2)); + + memcpy(buf+len, &head, sizeof(head)); + len+=sizeof(head); + memcpy(buf+len, packet, packet_size); + len+=packet_size; + send (connect->fd, buf, len, 0); + free(buf); + return 0; +} + +struct init2 +generate_init2(stream_t *stream) +{ + struct init2 ret; + memset(&ret,0,sizeof(ret)); + memcpy(ret.magick2,init2_magick2, + sizeof(ret.magick2)); + return ret; +} + +static int +ztv_http_connect_open(stream_t *stream, struct ztv_connect *connect) +{ + sprintf(connect->ipname,"%d.%d.%d.%d", + connect->ip[0],connect->ip[1], + connect->ip[2],connect->ip[3]); + connect->fd=connect2Server(connect->ipname,80,0); + if( connect->fd<0 ) + return -1; + return 0; + +} + +static int +ztv_http_connect_close(stream_t *stream, struct ztv_connect *connect) +{ + closesocket(connect->fd); + return 0; +} + + +static int +get_addr(stream_t *stream, char *channel) +{ + uint8_t buf[8192]; + struct addr_req2 ar2; + struct addr_resp2 r2; + int outlen; + struct ztv_connect addrcon; + zattoo_msg_type_t msg_type; + int size; + int t[4]; + int i; + uint8_t *packet; + struct zattoo_msg_parse_context *recvctx; + + memset(t,0,sizeof(t)); + /* Check if the address is given directly*/ + sscanf(channel,"%d.%d.%d.%d/%x",t,t+1,t+2,t+3, + &DATA(stream)->maincon.channel_id); + for(i=0;i<4;i++) + DATA(stream)->maincon.ip[i]=t[i]; + if(DATA(stream)->maincon.ip[3] && DATA(stream)->maincon.channel_id) + return 0; + + DATA(stream)->maincon.channel_id=0; + + memset(&addrcon,0,sizeof(addrcon)); + memcpy(addrcon.ip,addr_server,sizeof(addrcon.ip)); + + memcpy(buf, DATA(stream)->lticket, DATA(stream)->lticketlen); + strncpy((char *)(buf+DATA(stream)->lticketlen), channel, 200); + ztv_http_connect_open(stream, &addrcon); + + recvctx=zattoo_msg_parse_context_new(ztv_http_down,&addrcon); + + ztv_http_send_packet(stream, &addrcon, + buf, DATA(stream)->lticketlen+strlen(channel), + ZATTOO_MSG_TYPE_ADDRREQ1); + packet=zattoo_msg_get_packet(recvctx,&msg_type, &size); + if(!packet || msg_type!=ZATTOO_MSG_TYPE_ADDRRESP1 || size!=16) + { + free(packet); + zattoo_msg_parse_context_destroy(recvctx); + ztv_http_connect_close(stream, &addrcon); + return -1; + } + + outlen=RSA_private_encrypt(16, packet, ar2.sig, DATA(stream)->myrsa,1); + free(packet); + if(outlen<128) + return -1; + memcpy(buf,&ar2,sizeof(ar2)); + strcpy((char *)(buf+sizeof(ar2)),channel); + + ztv_http_send_packet(stream, &addrcon, + buf, sizeof(ar2)+strlen(channel), + ZATTOO_MSG_TYPE_ADDRREQ2); + packet=zattoo_msg_get_packet(recvctx,&msg_type, &size); + if(!packet || msg_type!=ZATTOO_MSG_TYPE_ADDRRESP2 || size<(signed)sizeof(r2)) + { + free(packet); + zattoo_msg_parse_context_destroy(recvctx); + ztv_http_connect_close(stream, &addrcon); + return -1; + } + memcpy(&r2,packet,sizeof(r2)); + free(packet); + memcpy(DATA(stream)->maincon.ip,r2.ipanswer,sizeof(r2.ipanswer)); + DATA(stream)->maincon.channel_id=be2me_32(r2.channel_id); + ztv_http_connect_close(stream, &addrcon); + zattoo_msg_parse_context_destroy(recvctx); + return 0; +} + +static int +load_rsa(stream_t *stream, char *fname) +{ + BIO *fbio=0; + EVP_PKEY *pkey; + fbio=BIO_new(BIO_s_file()); + if (BIO_read_filename(fbio,fname)<=0) + { + printf("Error reading %s\n", fname); + } + pkey=PEM_read_bio_PrivateKey(fbio,0,0,0); + if (pkey) + { + DATA(stream)->myrsa=EVP_PKEY_get1_RSA(pkey); + BIO_free_all(fbio); + free(pkey); + return 1; + } + BIO_free_all(fbio); + free(pkey); + printf("Error loading RSA key \n"); + return 0; +} + + +int +ztv_http_do_login(stream_t *stream, char *user, char *hash) +{ + uint8_t buf[8192], *bufptr=buf; + uint8_t obuf[512]; + unsigned char key[16]; + int olen; + int outlen; + struct ztv_connect logcon; + struct login_resp1 r1; + zattoo_msg_type_t msg_type; + int size; + EVP_CIPHER_CTX ctx; + uint8_t *packet; + int i, t; + int elen; + struct zattoo_msg_parse_context *recvctx; + + if(strlen(user)>63) + { + mp_msg(MSGT_NETWORK,MSGL_ERR,"Username too long\n"); + return -1; + } + + /* fixme: ugly*/ + for(i=0;i<16;i++) + { + sscanf(hash+2*i,"%2x", &t); + key[i]=t; + } + + // DATA(stream)->myrsa=RSA_generate_key(1024,65537,0,0); + load_rsa(stream,"rsa.pem"); + + memset(&logcon,0,sizeof(logcon)); + memcpy(logcon.ip,log_server,sizeof(logcon.ip)); + + memset(bufptr,0,64); + memcpy(bufptr, user, strlen(user)+1); + bufptr+=64; + bufptr+=BN_bn2bin(DATA(stream)->myrsa->n,bufptr); + bufptr+=elen=BN_bn2bin(DATA(stream)->myrsa->e,bufptr); + *bufptr=(elen&0xff00)>>8; + bufptr++; + *bufptr=elen&0xff; + bufptr++; + + ztv_http_connect_open(stream, &logcon); + recvctx=zattoo_msg_parse_context_new(ztv_http_down,&logcon); + + ztv_http_send_packet(stream, &logcon, + buf, bufptr-buf, + ZATTOO_MSG_TYPE_LOGINREQ1); + packet=zattoo_msg_get_packet(recvctx,&msg_type, &size); + + if(msg_type!=ZATTOO_MSG_TYPE_LOGINRESP1) + { + free(packet); + zattoo_msg_parse_context_destroy(recvctx); + ztv_http_connect_close(stream, &logcon); + return -1; + } + + if(size!=sizeof(r1)) + { + free(packet); + zattoo_msg_parse_context_destroy(recvctx); + ztv_http_connect_close(stream, &logcon); + return -1; + } + memcpy(&r1, packet, sizeof(r1)); + free(packet); + EVP_CIPHER_CTX_init(&ctx); + EVP_DecryptInit(&ctx, EVP_aes_128_cbc(), + key, + 0); + + EVP_DecryptUpdate (&ctx, obuf, &olen, r1.tosig_enc, + sizeof(r1.tosig_enc)); + if(!EVP_DecryptFinal(&ctx,obuf+olen,&t)) + { + zattoo_msg_parse_context_destroy(recvctx); + ztv_http_connect_close(stream, &logcon); + mp_msg(MSGT_NETWORK,MSGL_ERR,"Login failed\n"); + return -1; + } + olen+=t; + outlen=RSA_private_encrypt(olen, + obuf, + buf,DATA(stream)->myrsa,1); + EVP_CIPHER_CTX_cleanup(&ctx); + if(outlen<128) + return -1; + ztv_http_send_packet(stream, &logcon, + buf, outlen, + ZATTOO_MSG_TYPE_LOGINREQ2); + packet=zattoo_msg_get_packet(recvctx,&msg_type, &size); + + if(msg_type!=ZATTOO_MSG_TYPE_LOGINRESP2) + { + free(packet); + zattoo_msg_parse_context_destroy(recvctx); + ztv_http_connect_close(stream, &logcon); + return -1; + } + printf("%d %d\n", msg_type, size); + fflush(stdout); + + DATA(stream)->lticket=malloc(size); + DATA(stream)->lticketlen=size; + memcpy(DATA(stream)->lticket,packet,DATA(stream)->lticketlen); + { + FILE *f; + f=fopen("login.bin", "wb"); + fwrite(DATA(stream)->lticket,1,DATA(stream)->lticketlen, f); + fclose(f); + } + free(packet); + zattoo_msg_parse_context_destroy(recvctx); + ztv_http_connect_close(stream, &logcon); + return 0; +} + + + +static int +send_init(stream_t *stream, struct ztv_connect *connect) +{ + uint8_t init[4096]; + memset(init,0,sizeof(init)); + memcpy(init,init1_magick, + sizeof(init1_magick)); + memcpy(init+INIT1_LTICKETOFFSET,DATA(stream)->lticket, + DATA(stream)->lticketlen); + ztv_http_send_packet(stream, connect, + init, INIT1_LTICKETOFFSET+DATA(stream)->lticketlen, + ZATTOO_MSG_TYPE_INIT1); + return 0; +} + + + +static int +ztv_http_fill_buffer(stream_t *stream, char* buffer, int max_len) +{ + return recv(DATA(stream)->maincon.fd, buffer, max_len, 0); +} + +static void +ztv_http_close(struct stream_st *stream) +{ + ztv_http_connect_close (stream,&DATA(stream)->maincon); + DATA(stream)->myrsa->meth->finish(DATA(stream)->myrsa); + free(DATA(stream)); +} + +int +ztv_http_open (stream_t *stream) +{ + URL_t *url; + char *purl=stream->url+sizeof("ztvhttp://")-1, *virg, *virg2; + struct init2 init2i; + + stream->priv=malloc(sizeof(struct ztv_info)); + memset(stream->priv,0, sizeof(struct ztv_info)); + DATA(stream)->sendnum=0x35f; + + if(!(virg=strchr(purl,':'))) + return STREAM_ERROR; + *virg=0; + if(!(virg2=strchr(virg+1,':'))) + return STREAM_ERROR; + *virg2=0; + if(ztv_http_do_login(stream,purl, virg+1)<0) + { + mp_msg(MSGT_NETWORK,MSGL_ERR,"Login failed\n"); + return STREAM_ERROR; + } + if(get_addr(stream, virg2+1)<0) + { + mp_msg(MSGT_NETWORK,MSGL_ERR,"Geting address failed\n"); + return STREAM_ERROR; + } + ztv_http_connect_open(stream, &(DATA(stream)->maincon)); + send_init(stream, &(DATA(stream)->maincon)); + init2i=generate_init2(stream); + ztv_http_send_packet(stream, &(DATA(stream)->maincon), + &init2i, sizeof(init2i), ZATTOO_MSG_TYPE_INIT2); + + stream->fill_buffer=ztv_http_fill_buffer; + stream->close=ztv_http_close; + stream->flags=0; + return STREAM_OK; +} + +static int open_s(stream_t *stream,int mode, void* opts, int* file_format) { + + /* FIXME: proxy*/ + /* FIXME: opts and mode are ignored*/ + + *file_format=DEMUXER_TYPE_ZATTOO; + if (!strncmp(stream->url,"ztvhttp://",sizeof("ztvhttp://")-1)) + return ztv_http_open(stream); + + return STREAM_UNSUPORTED; +} + +stream_info_t stream_info_ztv = { + "zattoo stream", + "null", + "phcoder", + "Reverse engeneered", + open_s, + {"ztvhttp", NULL}, + NULL, + 0 // Urls are an option string +}; + Index: stream/stream.c =================================================================== --- stream/stream.c (révision 22949) +++ stream/stream.c (copie de travail) @@ -48,6 +48,7 @@ extern stream_info_t stream_info_rtsp; extern stream_info_t stream_info_rtp; extern stream_info_t stream_info_udp; +extern stream_info_t stream_info_ztv; extern stream_info_t stream_info_http1; extern stream_info_t stream_info_http2; #endif @@ -101,6 +102,7 @@ &stream_info_asf, &stream_info_pnm, &stream_info_rtsp, + &stream_info_ztv, #ifdef STREAMING_LIVE555 &stream_info_sdp, &stream_info_rtsp_sip, Index: Makefile =================================================================== --- Makefile (révision 22949) +++ Makefile (copie de travail) @@ -55,11 +55,45 @@ COMMON_LIBS = libmpcodecs/libmpcodecs.a \ libaf/libaf.a \ + stream/stream.a \ libmpdemux/libmpdemux.a \ - stream/stream.a \ libswscale/libswscale.a \ libvo/libosd.a \ +<<<<<<< .mine +LIBS_MPLAYER = libvo/libvo.a \ + libao2/libao2.a \ + input/libinput.a \ + +LIBS_MENCODER = libmpcodecs/libmpencoders.a \ + libmpdemux/libmpmux.a \ + +OBJS_COMMON = $(SRCS_COMMON:.c=.o) +OBJS_MPLAYER = $(SRCS_MPLAYER:.c=.o) +OBJS_MENCODER = $(SRCS_MENCODER:.c=.o) + +# Having this in libosdep.a is not enough. +OBJS_MPLAYER-$(TARGET_WIN32) += osdep/mplayer-rc.o + +MPLAYER_DEPS = $(OBJS_MPLAYER) $(OBJS_COMMON) $(LIBS_MPLAYER) $(COMMON_LIBS) +MENCODER_DEPS = $(OBJS_MENCODER) $(OBJS_COMMON) $(LIBS_MENCODER) $(COMMON_LIBS) + +PARTS = stream \ + libmpdemux \ + libmpcodecs \ + libavutil \ + libavcodec \ + libpostproc \ + libavformat \ + libswscale \ + libao2 \ + osdep \ + input \ + libvo \ + libaf \ + +======= +>>>>>>> .r22949 COMMON_LIBS-$(CONFIG_LIBAVFORMAT) += libavformat/libavformat.a COMMON_LIBS-$(CONFIG_LIBAVCODEC) += libavcodec/libavcodec.a COMMON_LIBS-$(CONFIG_LIBAVUTIL) += libavutil/libavutil.a Index: cfg-common.h =================================================================== --- cfg-common.h (révision 22949) +++ cfg-common.h (copie de travail) @@ -124,6 +124,7 @@ { "rawaudio", &demux_rawaudio_opts, CONF_TYPE_SUBCONFIG, 0, 0, 0, NULL}, { "rawvideo", &demux_rawvideo_opts, CONF_TYPE_SUBCONFIG, 0, 0, 0, NULL}, + { "ztvdemux", &demux_ztvdemux_opts, CONF_TYPE_SUBCONFIG, 0, 0, 0, NULL}, #ifdef HAVE_CDDA { "cdda", &cdda_opts, CONF_TYPE_SUBCONFIG, 0, 0, 0, NULL}, @@ -705,6 +706,8 @@ extern m_option_t xvid_dec_opts[]; #endif +extern m_option_t demux_ztvdemux_opts[]; + int dvd_parse_chapter_range(m_option_t*, const char*); #endif Index: libmpdemux/Makefile =================================================================== --- libmpdemux/Makefile (révision 22949) +++ libmpdemux/Makefile (copie de travail) @@ -44,6 +44,8 @@ video.c \ yuv4mpeg.c \ yuv4mpeg_ratio.c \ + zattoo.c \ + zattoo_msg.c \ SRCS_COMMON-$(CONFIG_LIBAVFORMAT) += demux_lavf.c SRCS_COMMON-$(CONFIG_LIBAVFORMAT_SO) += demux_lavf.c Index: libmpdemux/zattoo_msg.c =================================================================== --- libmpdemux/zattoo_msg.c (révision 0) +++ libmpdemux/zattoo_msg.c (révision 0) @@ -0,0 +1,214 @@ +#include +#include +#include +#include +#include +#include +#include "zattoo.h" +#include "mp_msg.h" +#include "libavutil/intreadwrite.h" +/* The magicks (first 12 bytes) of the messages */ +uint8_t zattoo_msg_magicks[NUM_ZATTOO_MSG_TYPE][12]= + { + [ZATTOO_MSG_TYPE_VIDEO] + ={0x03, 0x05, 0x01, 0x0f, 0x0a, 0x00, 0x7f, 0x00, 0x0a, 0x00, 0x00, 0x00}, + [ZATTOO_MSG_TYPE_AUDIO] + ={0x03, 0x05, 0x01, 0x11, 0x0a, 0x00, 0x7f, 0x00, 0x0a, 0x00, 0x00, 0x00}, + [ZATTOO_MSG_TYPE_META1] + ={0x03, 0x05, 0x01, 0x10, 0x0a, 0x00, 0x7f, 0x00, 0x0a, 0x00, 0x00, 0x00}, + [ZATTOO_MSG_TYPE_META2] + ={0x03, 0x05, 0x01, 0x12, 0x0a, 0x00, 0x7f, 0x00, 0x0a, 0x00, 0x00, 0x00}, + [ZATTOO_MSG_TYPE_STREAMHEADER] + ={0x03, 0x04, 0x00, 0x04, 0x0a, 0x00, 0x82, 0x14, 0x0a, 0x00, 0x13, 0x8b}, + [ZATTOO_MSG_TYPE_KEYUPDATE] + ={0x03, 0x04, 0x00, 0x04, 0x0a, 0x00, 0x2d, 0x14, 0x0a, 0x00, 0x13, 0x8b}, + [ZATTOO_MSG_TYPE_IGNORED1]//in stream + ={0x03, 0x04, 0x00, 0x04, 0x0a, 0x00, 0x19, 0x14, 0x0a, 0x00, 0x13, 0x8b}, + [ZATTOO_MSG_TYPE_IGNORED2] + ={0x03, 0x04, 0x00, 0x04, 0x0a, 0x00, 0x87, 0x14, 0x0a, 0x00, 0x13, 0x8b}, + [ZATTOO_MSG_TYPE_INIT1] + ={0x03, 0x04, 0x00, 0x04, 0x0a, 0x00, 0x02, 0x73, 0x0a, 0x00, 0x00, 0x00}, + [ZATTOO_MSG_TYPE_INIT2] + ={0x03, 0x04, 0x00, 0x04, 0x0a, 0x00, 0x07, 0x73, 0x0a, 0x00, 0x00, 0x00}, + [ZATTOO_MSG_TYPE_ADDRREQ1] + ={0x03, 0x04, 0x00, 0x04, 0x0a, 0x00, 0x01, 0x73, 0x0a, 0x00, 0x00, 0x00}, + [ZATTOO_MSG_TYPE_ADDRREQ2] + ={0x03, 0x04, 0x00, 0x04, 0x0a, 0x00, 0x21, 0x73, 0x0a, 0x00, 0x00, 0x00}, + [ZATTOO_MSG_TYPE_ADDRRESP1] + ={0x03, 0x04, 0x00, 0x04, 0x0a, 0x00, 0x81, 0x00, 0x0a, 0x00, 0x00, 0x00}, + [ZATTOO_MSG_TYPE_ADDRRESP2] + ={0x03, 0x04, 0x00, 0x04, 0x0a, 0x00, 0xa1, 0x00, 0x0a, 0x00, 0x00, 0x00}, + [ZATTOO_MSG_TYPE_LOGINREQ1] + ={0x03, 0x04, 0x00, 0x04, 0x0a, 0x00, 0x20, 0x73, 0x0a, 0x00, 0x00, 0x00}, + [ZATTOO_MSG_TYPE_LOGINRESP1] + ={0x03, 0x04, 0x00, 0x04, 0x0a, 0x00, 0xa0, 0x00, 0x0a, 0x00, 0x00, 0x00}, + [ZATTOO_MSG_TYPE_ERROR] + ={0x03, 0x04, 0x00, 0x04, 0x0a, 0x00, 0x05, 0x00, 0x0a, 0x00, 0x00, 0x00 } + }; + +/* initialize the parser */ +struct zattoo_msg_parse_context * +zattoo_msg_parse_context_new(int (*read_cb)(void *param, uint8_t *buf, int len), + void *param) +{ + struct zattoo_msg_parse_context *ret; + ret=(struct zattoo_msg_parse_context *)malloc + (sizeof(struct zattoo_msg_parse_context)); + ret->read_cb=read_cb; + ret->param=param; +} + +/* move the buffer towards the begining*/ +static int +zattoo_msg_move_buffer(struct zattoo_msg_parse_context *ctx) +{ + if(ctx->buf_pos!=0) + memmove(ctx->buffer, ctx->buffer+ctx->buf_pos, + ctx->buf_len); + ctx->buf_pos=0; + return 0; +} + + +/* Fill context buffer to at least min_size*/ +inline int +zattoo_msg_fill_buffer(struct zattoo_msg_parse_context *ctx, + int min_size) +{ + int was_read=0, was_read_total=0; + if (min_size && ctx->buf_len>=min_size) + return 0; + zattoo_msg_move_buffer(ctx); + while( ctx->buf_lenread_cb (ctx->param, ctx->buffer+ctx->buf_pos + +ctx->buf_len, + ZATTOO_MSG_BUFFER_SIZE + -ctx->buf_pos-ctx->buf_len); + if (was_read==0) + return -1; + if (was_read<0) + return was_read; + ctx->buf_len+=was_read; + was_read_total+=was_read; + } + return was_read_total; +} + +/* Determine the message type by comparing with magicks*/ +static zattoo_msg_type_t +zattoo_get_msg_type(uint8_t *head) +{ + int i; + for(i=0;ibuffer+ctx->buf_pos, pattern, psize)) + { + ctx->buf_pos++; + ctx->buf_len--; + ret=zattoo_msg_fill_buffer(ctx, psize); + if(ret<0) + return ret; + } + ctx->buf_pos+=psize; + ctx->buf_len-=psize; + + return 0; +} + + +/* Get a packet*/ +uint8_t * +zattoo_msg_get_packet(struct zattoo_msg_parse_context *ctx, + zattoo_msg_type_t *msg_type, int *packet_size) +{ + int report=1; + unsigned int i; + uint8_t *packet; + + /* Initialize the output to the error*/ + *msg_type=NUM_ZATTOO_MSG_TYPE; + *packet_size=0; + while(1) + { + /* Read the header*/ + if(zattoo_msg_fill_buffer(ctx, ZATTOO_MSG_HEADER_SIZE)<0) + return 0; + /* Skip the HTTP headers*/ + /* FIXME: Do we need to read the Content-Length?*/ + while (!memcmp("POST ", ctx->buffer+ctx->buf_pos, sizeof("POST ")-1) + || !memcmp("HTTP/", ctx->buffer+ctx->buf_pos, sizeof("HTTP/")-1)) + { + if(zattoo_msg_seek_to_pattern(ctx, (uint8_t *)"\r\n\r\n", 4)<0) + return 0; + if(zattoo_msg_fill_buffer(ctx, ZATTOO_MSG_HEADER_SIZE)<0) + return 0; + } + *msg_type=zattoo_get_msg_type(ctx->buffer+ctx->buf_pos); + *packet_size=AV_RB16(ctx->buffer+ctx->buf_pos + +ZATTOO_MSG_HEADER_OFFSET_SIZE); + + /* Do we know this message?*/ + if (*msg_type==NUM_ZATTOO_MSG_TYPE) + { + /* Unknown message. This shouldn't happen. Report only once */ + if(report) + { + mp_msg(MSGT_NETWORK,MSGL_ERR,"Unknown message "); + + for(i=0;ibuffer+ctx->buf_pos)[i]); + mp_msg(MSGT_NETWORK,MSGL_ERR," trying to resync\n"); + report=0; + } + /*Skip a byte*/ + ctx->buf_pos++; + ctx->buf_len--; + continue; + } + ctx->buf_pos+=ZATTOO_MSG_HEADER_SIZE; + ctx->buf_len-=ZATTOO_MSG_HEADER_SIZE; + if(*packet_size>ZATTOO_MSG_BUFFER_SIZE) + { + mp_msg(MSGT_NETWORK,MSGL_ERR,"giant of size %d dropped\n", + *packet_size); + *packet_size=0; + *msg_type=NUM_ZATTOO_MSG_TYPE; + return 0; + } + if(zattoo_msg_fill_buffer(ctx, *packet_size)<0) + { + *packet_size=0; + *msg_type=NUM_ZATTOO_MSG_TYPE; + return 0; + } + packet=(uint8_t *)malloc(*packet_size); + memcpy(packet, ctx->buffer+ctx->buf_pos, *packet_size); + ctx->buf_pos+=*packet_size; + ctx->buf_len-=*packet_size; + return packet; + } +} + + +/*Destroy the parser*/ +void +zattoo_msg_parse_context_destroy(struct zattoo_msg_parse_context *ctx) +{ + free(ctx); +} Index: libmpdemux/zattoo.c =================================================================== --- libmpdemux/zattoo.c (révision 0) +++ libmpdemux/zattoo.c (révision 0) @@ -0,0 +1,617 @@ +#include "libavutil/common.h" +#include "libavutil/oaep.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "mp_msg.h" +#include "help_mp.h" + +#include +#include +#include + +#include +#include "zattoo.h" +#include "stream.h" +#include "demuxer.h" +#include "stheader.h" +#include "m_option.h" + +static float audiofreq=48000; +static float videofreq=90000; + +m_option_t demux_ztvdemux_opts[] = { + { "audiofreq", &audiofreq, CONF_TYPE_FLOAT,CONF_RANGE,1.0,200000.0, NULL }, + { "videofreq", &videofreq, CONF_TYPE_FLOAT,CONF_RANGE,1.0,200000.0, NULL }, + {NULL, NULL, 0, 0, 0, 0, NULL} +}; + + +/* Zattoo codec parameters. FIXME: perhaps is it in the header?*/ +static uint8_t h264init[]={0x00,0x00,0x00,0x01,0x67,0x4d,0x40,0x33, + 0x92,0x54,0x0b,0x04,0xb4,0x20,0x00,0x00, + 0x03,0x00,0x40,0x00,0x00,0x0c,0xd1,0xe3, + 0x06,0x54,0x00,0x00,0x00,0x01,0x68,0xee, + 0x3c,0x80}; +static uint8_t audioprivate[2]={0x11,0x90}; +#define ZATTOO_AUDIO_TIMEUNIT audiofreq +#define ZATTOO_VIDEO_TIMEUNIT videofreq + +#define me2be_64(x) be2me_64(x) +#define me2be_32(x) be2me_32(x) +#define me2be_16(x) be2me_16(x) +#define QUEUE_LEN 30 + + +#define FNUMBERL3_MARGE 0x400 +#define min(a,b) (((a)<(b))?(a):(b)) + + +struct l2_header +{ + uint8_t kselector; + uint8_t iv[16]; +} __attribute__ ((packed)); + +struct l3_header +{ + /*TORES*/ + uint16_t magick1; //8060/80e0 ??? + uint16_t fnumber; /*be*/ + uint32_t timepos; /* !! different units !!*/ + uint32_t magick2;// some stream id???? + /*TORES*/ + uint8_t flags1, flags2; +} __attribute__ ((packed)); + +struct key_update_msg +{ + uint8_t iv[0x10]; + uint8_t enc[0x30]; +} __attribute__ ((packed)); + + +struct stream_header +{ + uint8_t sth1[0xa0]; + uint8_t keys_enc[0x80]; +} __attribute__ ((packed)); + +struct key_sent +{ + uint8_t key_id; + uint8_t sth1[2]; + uint8_t key[16]; +} __attribute__ ((packed)); + +struct header_keys_dec +{ + uint8_t seskey[16]; + struct key_sent keys[2]; +} __attribute__ ((packed)); + + +struct frame +{ + struct l3_header head; + uint8_t *data; + int len; +}; + + +struct key_update_msg_dec +{ + uint8_t sth1[24]; + struct key_sent key; +} __attribute__ ((packed)); + + +struct ztv_demux_info +{ + RSA *myrsa; + uint8_t keys[256][16]; + int hasakey[256]; + uint8_t seskey[16]; + int h264sent; + int naudpackets, nvidpackets; + uint32_t audiostart, videostart; + struct frame video_queue[QUEUE_LEN+1], audio_queue[QUEUE_LEN+1]; + int video_queue_current_size; + int audio_queue_current_size; + int video_inited; + uint8_t videobuf[409600]; + int videobuf_pos; + int videobuf_time; + uint32_t sendnum; + struct zattoo_msg_parse_context *msgctx; +}; + +#define DATA(x) ((struct ztv_demux_info *)x->priv) + +static int +cmp_fnumberl3(struct l3_header a, struct l3_header b) +{ + /* Fix the overflow*/ + if (be2me_16(a.fnumber)(uint16_t)~FNUMBERL3_MARGE) + return +1; + if (be2me_16(b.fnumber)(uint16_t)~FNUMBERL3_MARGE) + return -1; + if (be2me_16(a.fnumber)be2me_16(b.fnumber)) + return +1; + return 0; +} + +static void +push_frame(struct frame *frame_queue, + int *frame_queue_current_size, + unsigned char *buf, + unsigned int len) +{ + int i,j; + struct frame cframe; + + if (len<=sizeof(cframe.head)) + { + /*error message*/ + return; + } + memcpy(&cframe.head,buf,sizeof(cframe.head)); + cframe.data=(unsigned char *)malloc(len-sizeof(cframe.head)); + memcpy(cframe.data,buf+sizeof(cframe.head),len-sizeof(cframe.head)); + cframe.len=len-sizeof(cframe.head); + + for(i=0;i<*frame_queue_current_size;i++) + if(cmp_fnumberl3(frame_queue[i].head,cframe.head)>0) + break; + for(j=*frame_queue_current_size-1;j>=i;j--) + frame_queue[j+1]=frame_queue[j]; + frame_queue[i]=cframe; + + (*frame_queue_current_size)++; +} + +struct frame +pop_frame(struct frame *frame_queue, + int *frame_queue_current_size) +{ + struct frame cframe; + int i; + cframe=frame_queue[0]; + for(i=1;i<*frame_queue_current_size;i++) + frame_queue[i-1]=frame_queue[i]; + (*frame_queue_current_size)--; + // printf("%x\n", be2me_16(cframe.head.fnumber)); + return cframe; +} + +void +free_queue(struct frame *frame_queue, + int *frame_queue_current_size) +{ + int i; + return; + for(i=0;i<*frame_queue_current_size;i++) + free (frame_queue[i].data); + *frame_queue_current_size=0; +} + + +static int +ztv_http_parse_demuxer_packet(demuxer_t *demuxer, + struct zattoo_msg_parse_context *ctx, + uint8_t *packet, unsigned int packet_size, + zattoo_msg_type_t msg_type) +{ + struct l2_header headl2; + EVP_CIPHER_CTX encctx; + unsigned char obuf[50000]; + int olen=0; + int t=0; + + memset(&encctx,0, sizeof(encctx)); + if(packet_size<=sizeof(struct l2_header)) + { + mp_msg(MSGT_NETWORK,MSGL_ERR,"dwarf of size %d dropped\n", packet_size); + return -1; + } + memcpy(&headl2, packet, sizeof(struct l2_header)); + if(!DATA(demuxer)->hasakey[headl2.kselector]) + { + // mp_msg(MSGT_NETWORK,MSGL_ERR,"No key:%02x\n",headl2.kselector); + return -1; + } + EVP_DecryptInit(&encctx, EVP_aes_128_cbc(), + DATA(demuxer)->keys[headl2.kselector], + headl2.iv); + EVP_DecryptUpdate (&encctx, obuf, &olen, packet+sizeof(struct l2_header), + packet_size-sizeof(struct l2_header)); + EVP_DecryptFinal(&encctx,obuf+olen,&t); + olen+=t; + EVP_CIPHER_CTX_cleanup(&encctx); + + /* Push it to appripriate queue*/ + switch(msg_type) + { + case ZATTOO_MSG_TYPE_AUDIO: + push_frame(DATA(demuxer)->audio_queue, + &DATA(demuxer)->audio_queue_current_size, obuf,olen); + if(DATA(demuxer)->naudpackets==0) + DATA(demuxer)->audiostart=be2me_32(((struct l3_header *)obuf)->timepos); + DATA(demuxer)->naudpackets++; + break; + case ZATTOO_MSG_TYPE_VIDEO: + push_frame(DATA(demuxer)->video_queue, + &DATA(demuxer)->video_queue_current_size, obuf,olen); + if(DATA(demuxer)->nvidpackets==0) + DATA(demuxer)->videobuf_time=DATA(demuxer)->videostart=be2me_32(((struct l3_header *)obuf)->timepos); + DATA(demuxer)->nvidpackets++; + break; + default: + mp_msg(MSGT_NETWORK,MSGL_ERR,"Unexpected packet %d in ztv_http_parse_demuxer_packet\n", + msg_type); + break; + } + return msg_type; + +} + +static int +ztv_http_parse_keyupdate(demuxer_t *demuxer, + struct zattoo_msg_parse_context *ctx, + uint8_t *packet, int packet_size, + zattoo_msg_type_t msg_type) +{ + struct key_update_msg *kupd; + struct key_update_msg_dec *kupd_dec; + EVP_CIPHER_CTX encctx; + unsigned char obuf[4096]; + int olen,t; + memset(&encctx,0, sizeof(encctx)); + + if(packet_size!=sizeof(struct key_update_msg)) + return -1; + kupd=(struct key_update_msg *) packet; + + EVP_DecryptInit(&encctx, EVP_aes_128_cbc(), + DATA(demuxer)->seskey, + kupd->iv); + EVP_DecryptUpdate (&encctx, obuf, &olen, kupd->enc, + sizeof(kupd->enc)); + EVP_DecryptFinal(&encctx,obuf+olen,&t); + olen+=t; + EVP_CIPHER_CTX_cleanup(&encctx); + if(olen!=sizeof(struct key_update_msg_dec)) + return -1; + + kupd_dec=(struct key_update_msg_dec *)obuf; + memcpy(DATA(demuxer)->keys[kupd_dec->key.key_id], &(kupd_dec->key.key),16); + DATA(demuxer)->hasakey[kupd_dec->key.key_id]=1; + return 0; +} + +static int +ztv_http_parse_streamheader(demuxer_t *demuxer, struct zattoo_msg_parse_context *ctx, + uint8_t *packet, int packet_size, + zattoo_msg_type_t msg_type) +{ + + unsigned char buf2[1024], buf3[1024]; + int outlen; + struct stream_header head; + struct header_keys_dec keys; + + + if(packet_size!=sizeof(struct stream_header)) + return -1; + + memcpy(&head, packet, sizeof(head)); + outlen=DATA(demuxer)->myrsa->meth->rsa_priv_dec(sizeof(head.keys_enc), + head.keys_enc, + buf3,DATA(demuxer)->myrsa, + RSA_NO_PADDING); + outlen = av_parse_oaep (buf3+1, buf2, outlen-1); + + + if(outlen<(signed int)sizeof(keys)) + return -1; + + memcpy(&keys,buf2, sizeof(keys)); + memcpy (DATA(demuxer)->seskey, keys.seskey, 16); + memcpy (DATA(demuxer)->keys[keys.keys[0].key_id], keys.keys[0].key, 16); + memcpy (DATA(demuxer)->keys[keys.keys[1].key_id], keys.keys[1].key, 16); + DATA(demuxer)->hasakey[keys.keys[0].key_id]=1; + DATA(demuxer)->hasakey[keys.keys[1].key_id]=1; + return 0; +} + +static zattoo_msg_type_t +ztv_http_dispatch_packet(demuxer_t *demuxer, + struct zattoo_msg_parse_context *ctx) +{ + uint8_t *packet; + zattoo_msg_type_t msg_type; + int size; + packet=zattoo_msg_get_packet(ctx, &msg_type, &size); + switch(msg_type) + { + case ZATTOO_MSG_TYPE_VIDEO: + case ZATTOO_MSG_TYPE_AUDIO: + ztv_http_parse_demuxer_packet(demuxer, ctx, packet, + size, msg_type); + break; + case ZATTOO_MSG_TYPE_KEYUPDATE: + ztv_http_parse_keyupdate(demuxer, ctx, packet, + size, msg_type); + break; + case ZATTOO_MSG_TYPE_STREAMHEADER: + ztv_http_parse_streamheader(demuxer, connect, packet, + size, msg_type); + break; + // ignored messages + case ZATTOO_MSG_TYPE_META1: + case ZATTOO_MSG_TYPE_META2: + case ZATTOO_MSG_TYPE_IGNORED1: + case ZATTOO_MSG_TYPE_IGNORED2: + break; + + /* EOF */ + case NUM_ZATTOO_MSG_TYPE: + break; + + default: + mp_msg(MSGT_NETWORK,MSGL_ERR,"Unexpected packet %d in ztv_http_dispatch_packet\n", + msg_type); + break; + } + free(packet); + return msg_type; +} + + + +static void +ztv_matroska_write_audio(demuxer_t *demuxer,uint8_t *buf, uint64_t timepos, + int len, + int numoflaces) +{ + uint8_t *curptr; + uint16_t *lacearr; + int i; + + // return 0; + lacearr=((uint16_t *)buf); + curptr=buf+numoflaces*2; + for(i=0;ibuffer,curptr,be2me_16(lacearr[i])/8); + resize_demux_packet(dp, len); + dp->pos=0; + dp->pts=timepos/ZATTOO_AUDIO_TIMEUNIT; + dp->flags=0; + ds_add_packet(demuxer->audio,dp); + curptr+=be2me_16(lacearr[i])/8; + } +} + +static int +load_rsa( demuxer_t* demuxer , char *fname) +{ + BIO *fbio=0; + EVP_PKEY *pkey; + fbio=BIO_new(BIO_s_file()); + if (BIO_read_filename(fbio,fname)<=0) + { + printf("Error reading %s\n", fname); + } + pkey=PEM_read_bio_PrivateKey(fbio,0,0,0); + if (pkey) + { + DATA(demuxer)->myrsa=EVP_PKEY_get1_RSA(pkey); + BIO_free_all(fbio); + return 1; + } + BIO_free_all(fbio); + printf("Error loading RSA key \n"); + return 0; +} + +static demuxer_t* demux_open_zattoo ( demuxer_t* demuxer ) +{ + sh_video_t *sh_video = NULL; + sh_audio_t *sh_audio = NULL; + struct ztv_demux_info* priv = + (struct ztv_demux_info*) malloc ( sizeof (struct ztv_demux_info) ); + demuxer->priv = priv; + memset(priv,0,sizeof(priv)); + + load_rsa(demuxer, "rsa.pem"); + + /* Go to the start */ + stream_reset(demuxer->stream); + DATA(demuxer)->msgctx + =zattoo_msg_parse_context_new(stream_read,demuxer->stream); + + demuxer->seekable=0; + + /* Initialize video stream with fixed parameters */ + /* FIXME: perhaps some of parameters are in the head*/ + sh_video = new_sh_video ( demuxer, 0 ); + demuxer->video->sh = sh_video; + sh_video->ds = demuxer->video; + sh_video->format = mmioFOURCC('a', 'v', 'c', '1');; + sh_video->disp_w = 352; + sh_video->disp_h = 288; + sh_video->aspect = (float) 352.0/288.0; + sh_video->fps = 25.0; + sh_video->frametime = 1 / 25.0; + + /* Same thing with the audio*/ + + sh_audio = new_sh_audio(demuxer, 0); + demuxer->audio->sh = sh_audio; + sh_audio->ds = demuxer->audio; + //sh_audio->wf = malloc (sizeof(*sh_audio->wf)); + sh_audio->format = 0xff;//mmioFOURCC('M','P','4','A'); + + //sh_audio->wf->wFormatTag = 0xff;// mmioFOURCC('M','P','4','A'); + //sh_audio->channels = 2; + //sh_audio->wf->nChannels = 2; + // sh_audio->samplesize = 2; + // sh_audio->wf->wBitsPerSample = 16; + //sh_audio->wf->nAvgBytesPerSec = 16000; + //sh_audio->wf->nBlockAlign = 1024; + sh_audio->samplerate = audiofreq; + //sh_audio->wf->nSamplesPerSec = audiofreq; + //sh_audio->wf->cbSize = 0; + sh_audio->codecdata_len=sizeof(audioprivate); + sh_audio->codecdata=(unsigned char *)malloc(sizeof(audioprivate)); + memcpy(sh_audio->codecdata,audioprivate,sizeof(audioprivate)); + + return demuxer; +} + +static void demux_close_zattoo(demuxer_t* demuxer) +{ + zattoo_msg_parse_context_destroy(DATA(demuxer)->msgctx); + free_queue(DATA(demuxer)->video_queue, + &DATA(demuxer)->video_queue_current_size); + free_queue(DATA(demuxer)->audio_queue, + &DATA(demuxer)->audio_queue_current_size); + free(DATA(demuxer)); +} + +static int demux_zattoo_fill_buffer ( demuxer_t *demuxer, demux_stream_t *ds ) +{ + int t; + zattoo_msg_type_t lbt=NUM_ZATTOO_MSG_TYPE; + struct frame curf; + + while (DATA(demuxer)->video_queue_current_size + +DATA(demuxer)->audio_queue_current_sizemsgctx)); + if(t==NUM_ZATTOO_MSG_TYPE || t<0) + return 0; + if(t==ZATTOO_MSG_TYPE_VIDEO || t==ZATTOO_MSG_TYPE_AUDIO) + lbt=t; + } + switch(lbt) + { + /*video*/ + case ZATTOO_MSG_TYPE_VIDEO: + curf=pop_frame(DATA(demuxer)->video_queue, + &DATA(demuxer)->video_queue_current_size); + if (!DATA(demuxer)->video_inited + && !(curf.head.flags1==0x7c && curf.head.flags2==0x85)) + { + free(curf.data); + return 1; + } + DATA(demuxer)->video_inited=1; + if(DATA(demuxer)->videobuf_pos + &&((curf.head.flags1==0x5c && curf.head.flags2==0x81) + ||(curf.head.flags1==0x7c && curf.head.flags2==0x85) + ||(curf.head.flags1==0x41 && curf.head.flags2==0x9a))) + { + /* FIXME: integer overflow*/ + demux_packet_t* dp=new_demux_packet(DATA(demuxer)->videobuf_pos); + memcpy(dp->buffer,DATA(demuxer)->videobuf, + DATA(demuxer)->videobuf_pos); + resize_demux_packet(dp, DATA(demuxer)->videobuf_pos); + dp->pos=0; + dp->pts=(DATA(demuxer)->videobuf_time + -DATA(demuxer)->videostart)/ZATTOO_VIDEO_TIMEUNIT; + dp->flags=0x10; + ds_add_packet(demuxer->video,dp); + + DATA(demuxer)->videobuf_time=be2me_32(curf.head.timepos); + DATA(demuxer)->videobuf_pos=0; + } + if(!DATA(demuxer)->h264sent) + { + memcpy(DATA(demuxer)->videobuf+DATA(demuxer)->videobuf_pos, + h264init, sizeof(h264init)); + DATA(demuxer)->videobuf_pos+=sizeof(h264init); + DATA(demuxer)->h264sent=1; + } + /* FIXME: quite ugly*/ + if(curf.head.flags1==0x5c && curf.head.flags2==0x81) + { + memcpy(DATA(demuxer)->videobuf+DATA(demuxer)->videobuf_pos, + "\0\0\0\1\x41", 5); + DATA(demuxer)->videobuf_pos+=5; + } + // I-frame + if(curf.head.flags1==0x7c && curf.head.flags2==0x85) + { + memcpy(DATA(demuxer)->videobuf+DATA(demuxer)->videobuf_pos, + "\0\0\0\1\x65", 5); + DATA(demuxer)->videobuf_pos+=5; + } + if(curf.head.flags1==0x41 && curf.head.flags2==0x9a) + { + memcpy(DATA(demuxer)->videobuf+DATA(demuxer)->videobuf_pos, + "\0\0\0\1\x41\x9a", 6); + DATA(demuxer)->videobuf_pos+=6; + } + + memcpy(DATA(demuxer)->videobuf+DATA(demuxer)->videobuf_pos, + curf.data,curf.len); + DATA(demuxer)->videobuf_pos+=curf.len; + free(curf.data); + break; + + /*audio*/ + case ZATTOO_MSG_TYPE_AUDIO: + curf=pop_frame(DATA(demuxer)->audio_queue, &DATA(demuxer)->audio_queue_current_size); + if (!DATA(demuxer)->video_inited ) + { + free(curf.data); + return 1; + } + /* FIXME: integer overflow*/ + ztv_matroska_write_audio + (demuxer,curf.data, + be2me_32(curf.head.timepos)-DATA(demuxer)->audiostart, + curf.len, curf.head.flags2>>4); + free(curf.data); + break; + default: + mp_msg(MSGT_NETWORK,MSGL_ERR,"Unexpected packet %d in ztv_http_parse_stream_packet\n", + lbt); + break; + + } + return 1; +} + + + +demuxer_desc_t demuxer_desc_zattoo = { + "Zattoo demuxer", + "ztv", + "ZattooVideo", + "phcoder", + "", + DEMUXER_TYPE_ZATTOO, + 0, // safe autodetect + 0,//nuv_check_file, + demux_zattoo_fill_buffer, + demux_open_zattoo, + demux_close_zattoo, + 0,//demux_seek_nuv, + NULL +}; Index: libmpdemux/zattoo.h =================================================================== --- libmpdemux/zattoo.h (révision 0) +++ libmpdemux/zattoo.h (révision 0) @@ -0,0 +1,55 @@ +#include +/* Message types */ +enum _zattoo_msg_type_t + { + ZATTOO_MSG_TYPE_VIDEO, + ZATTOO_MSG_TYPE_AUDIO, + ZATTOO_MSG_TYPE_META1,//ignored + ZATTOO_MSG_TYPE_META2,//ignored + ZATTOO_MSG_TYPE_STREAMHEADER, + ZATTOO_MSG_TYPE_KEYUPDATE, + ZATTOO_MSG_TYPE_IGNORED1,//ignored + ZATTOO_MSG_TYPE_IGNORED2,//ignored + ZATTOO_MSG_TYPE_INIT1, + ZATTOO_MSG_TYPE_INIT2, + ZATTOO_MSG_TYPE_ADDRREQ1, + ZATTOO_MSG_TYPE_ADDRREQ2, + ZATTOO_MSG_TYPE_ADDRRESP1, + ZATTOO_MSG_TYPE_ADDRRESP2, + ZATTOO_MSG_TYPE_LOGINREQ1, + ZATTOO_MSG_TYPE_LOGINRESP1, + ZATTOO_MSG_TYPE_ERROR, + NUM_ZATTOO_MSG_TYPE + }; +typedef enum _zattoo_msg_type_t zattoo_msg_type_t; + +/* The magicks (first 12 bytes) of the messages */ +extern uint8_t zattoo_msg_magicks[NUM_ZATTOO_MSG_TYPE][12]; + +/* Apparently theese 2 share the same magick*/ +#define ZATTOO_MSG_TYPE_LOGINREQ2 ZATTOO_MSG_TYPE_ADDRREQ2 +#define ZATTOO_MSG_TYPE_LOGINRESP2 ZATTOO_MSG_TYPE_ADDRRESP2 + +/* Message parser */ +#define ZATTOO_MSG_BUFFER_SIZE 131072 +struct zattoo_msg_parse_context +{ + uint8_t buffer[ZATTOO_MSG_BUFFER_SIZE]; + int buf_pos; + int buf_len; + int (*read_cb)(void *param, uint8_t *buf, int len); + void *param; +}; +struct zattoo_msg_parse_context * +zattoo_msg_parse_context_new(int (*read_cb)(void *param, uint8_t *buf, int len), + void *param); +uint8_t * +zattoo_msg_get_packet(struct zattoo_msg_parse_context *ctx, + zattoo_msg_type_t *msg_type, int *packet_size); +void +zattoo_msg_parse_context_destroy(struct zattoo_msg_parse_context *ctx); + + /*Message header */ +#define ZATTOO_MSG_HEADER_OFFSET_SIZE 38 +#define ZATTOO_MSG_HEADER_SIZE 40 + Index: libmpdemux/demuxer.c =================================================================== --- libmpdemux/demuxer.c (révision 22949) +++ libmpdemux/demuxer.c (copie de travail) @@ -66,6 +66,7 @@ extern demuxer_desc_t demuxer_desc_lavf; extern demuxer_desc_t demuxer_desc_aac; extern demuxer_desc_t demuxer_desc_nut; +extern demuxer_desc_t demuxer_desc_zattoo; demuxer_desc_t* demuxer_list[] = { &demuxer_desc_rawaudio, @@ -128,6 +129,7 @@ #ifdef HAVE_XMMS &demuxer_desc_xmms, #endif + &demuxer_desc_zattoo, NULL }; Index: libmpdemux/demuxer.h =================================================================== --- libmpdemux/demuxer.h (révision 22949) +++ libmpdemux/demuxer.h (copie de travail) @@ -55,11 +55,12 @@ #define DEMUXER_TYPE_MPEG_PES 41 #define DEMUXER_TYPE_MPEG_GXF 42 #define DEMUXER_TYPE_NUT 43 +#define DEMUXER_TYPE_ZATTOO 44 // This should always match the higest demuxer type number. // Unless you want to disallow users to force the demuxer to some types #define DEMUXER_TYPE_MIN 0 -#define DEMUXER_TYPE_MAX 43 +#define DEMUXER_TYPE_MAX 44 #define DEMUXER_TYPE_DEMUXERS (1<<16) // A virtual demuxer type for the network code