1/* 2 * Copyright (C) 2008 Ramiro Polla <ramiro@lisha.ufsc.br> 3 * 4 * This file is part of FFmpeg. 5 * 6 * FFmpeg is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * FFmpeg is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with FFmpeg; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 */ 20 21#include "libavcodec/bytestream.h" 22#include "avformat.h" 23 24#define HEADER_SIZE 24 25 26/* 27 * Header structure: 28 * uint16_t ss; // struct size 29 * uint16_t width; // frame width 30 * uint16_t height; // frame height 31 * uint16_t ff; // keyframe + some other info(???) 32 * uint32_t size; // size of data 33 * uint32_t fourcc; // ML20 34 * uint32_t u3; // ? 35 * uint32_t ts; // time 36 */ 37 38static int msnwc_tcp_probe(AVProbeData *p) 39{ 40 int i; 41 42 for(i = 0 ; i + HEADER_SIZE <= p->buf_size ; i++) { 43 uint16_t width, height; 44 uint32_t fourcc; 45 const uint8_t *bytestream = p->buf+i; 46 47 if(bytestream_get_le16(&bytestream) != HEADER_SIZE) 48 continue; 49 width = bytestream_get_le16(&bytestream); 50 height = bytestream_get_le16(&bytestream); 51 if(!(width==320 && height==240) && !(width==160 && height==120)) 52 continue; 53 bytestream += 2; // keyframe 54 bytestream += 4; // size 55 fourcc = bytestream_get_le32(&bytestream); 56 if(fourcc != MKTAG('M', 'L', '2', '0')) 57 continue; 58 59 if(i) { 60 if(i < 14) /* starts with SwitchBoard connection info */ 61 return AVPROBE_SCORE_MAX / 2; 62 else /* starts in the middle of stream */ 63 return AVPROBE_SCORE_MAX / 3; 64 } else { 65 return AVPROBE_SCORE_MAX; 66 } 67 } 68 69 return -1; 70} 71 72static int msnwc_tcp_read_header(AVFormatContext *ctx, AVFormatParameters *ap) 73{ 74 ByteIOContext *pb = ctx->pb; 75 AVCodecContext *codec; 76 AVStream *st; 77 78 st = av_new_stream(ctx, 0); 79 if(!st) 80 return AVERROR(ENOMEM); 81 82 codec = st->codec; 83 codec->codec_type = AVMEDIA_TYPE_VIDEO; 84 codec->codec_id = CODEC_ID_MIMIC; 85 codec->codec_tag = MKTAG('M', 'L', '2', '0'); 86 87 av_set_pts_info(st, 32, 1, 1000); 88 89 /* Some files start with "connected\r\n\r\n". 90 * So skip until we find the first byte of struct size */ 91 while(get_byte(pb) != HEADER_SIZE && !url_feof(pb)); 92 93 if(url_feof(pb)) { 94 av_log(ctx, AV_LOG_ERROR, "Could not find valid start."); 95 return -1; 96 } 97 98 return 0; 99} 100 101static int msnwc_tcp_read_packet(AVFormatContext *ctx, AVPacket *pkt) 102{ 103 ByteIOContext *pb = ctx->pb; 104 uint16_t keyframe; 105 uint32_t size, timestamp; 106 107 url_fskip(pb, 1); /* one byte has been read ahead */ 108 url_fskip(pb, 2); 109 url_fskip(pb, 2); 110 keyframe = get_le16(pb); 111 size = get_le32(pb); 112 url_fskip(pb, 4); 113 url_fskip(pb, 4); 114 timestamp = get_le32(pb); 115 116 if(!size || av_get_packet(pb, pkt, size) != size) 117 return -1; 118 119 url_fskip(pb, 1); /* Read ahead one byte of struct size like read_header */ 120 121 pkt->pts = timestamp; 122 pkt->dts = timestamp; 123 pkt->stream_index = 0; 124 125 /* Some aMsn generated videos (or was it Mercury Messenger?) don't set 126 * this bit and rely on the codec to get keyframe information */ 127 if(keyframe&1) 128 pkt->flags |= AV_PKT_FLAG_KEY; 129 130 return HEADER_SIZE + size; 131} 132 133AVInputFormat msnwc_tcp_demuxer = { 134 "msnwctcp", 135 NULL_IF_CONFIG_SMALL("MSN TCP Webcam stream"), 136 0, 137 msnwc_tcp_probe, 138 msnwc_tcp_read_header, 139 msnwc_tcp_read_packet, 140}; 141