00001 /* 00002 * Copyright (C) 2008 Ramiro Polla 00003 * 00004 * This file is part of FFmpeg. 00005 * 00006 * FFmpeg is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU Lesser General Public 00008 * License as published by the Free Software Foundation; either 00009 * version 2.1 of the License, or (at your option) any later version. 00010 * 00011 * FFmpeg is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 * Lesser General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Lesser General Public 00017 * License along with FFmpeg; if not, write to the Free Software 00018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00019 */ 00020 00021 #include "libavcodec/bytestream.h" 00022 #include "avformat.h" 00023 #include "internal.h" 00024 00025 #define HEADER_SIZE 24 00026 00027 /* 00028 * Header structure: 00029 * uint16_t ss; // struct size 00030 * uint16_t width; // frame width 00031 * uint16_t height; // frame height 00032 * uint16_t ff; // keyframe + some other info(???) 00033 * uint32_t size; // size of data 00034 * uint32_t fourcc; // ML20 00035 * uint32_t u3; // ? 00036 * uint32_t ts; // time 00037 */ 00038 00039 static int msnwc_tcp_probe(AVProbeData *p) 00040 { 00041 int i; 00042 00043 for(i = 0 ; i + HEADER_SIZE <= p->buf_size ; i++) { 00044 uint16_t width, height; 00045 uint32_t fourcc; 00046 const uint8_t *bytestream = p->buf+i; 00047 00048 if(bytestream_get_le16(&bytestream) != HEADER_SIZE) 00049 continue; 00050 width = bytestream_get_le16(&bytestream); 00051 height = bytestream_get_le16(&bytestream); 00052 if(!(width==320 && height==240) && !(width==160 && height==120)) 00053 continue; 00054 bytestream += 2; // keyframe 00055 bytestream += 4; // size 00056 fourcc = bytestream_get_le32(&bytestream); 00057 if(fourcc != MKTAG('M', 'L', '2', '0')) 00058 continue; 00059 00060 if(i) { 00061 if(i < 14) /* starts with SwitchBoard connection info */ 00062 return AVPROBE_SCORE_MAX / 2; 00063 else /* starts in the middle of stream */ 00064 return AVPROBE_SCORE_MAX / 3; 00065 } else { 00066 return AVPROBE_SCORE_MAX; 00067 } 00068 } 00069 00070 return -1; 00071 } 00072 00073 static int msnwc_tcp_read_header(AVFormatContext *ctx, AVFormatParameters *ap) 00074 { 00075 AVIOContext *pb = ctx->pb; 00076 AVCodecContext *codec; 00077 AVStream *st; 00078 00079 st = avformat_new_stream(ctx, NULL); 00080 if(!st) 00081 return AVERROR(ENOMEM); 00082 00083 codec = st->codec; 00084 codec->codec_type = AVMEDIA_TYPE_VIDEO; 00085 codec->codec_id = CODEC_ID_MIMIC; 00086 codec->codec_tag = MKTAG('M', 'L', '2', '0'); 00087 00088 avpriv_set_pts_info(st, 32, 1, 1000); 00089 00090 /* Some files start with "connected\r\n\r\n". 00091 * So skip until we find the first byte of struct size */ 00092 while(avio_r8(pb) != HEADER_SIZE && !url_feof(pb)); 00093 00094 if(url_feof(pb)) { 00095 av_log(ctx, AV_LOG_ERROR, "Could not find valid start."); 00096 return -1; 00097 } 00098 00099 return 0; 00100 } 00101 00102 static int msnwc_tcp_read_packet(AVFormatContext *ctx, AVPacket *pkt) 00103 { 00104 AVIOContext *pb = ctx->pb; 00105 uint16_t keyframe; 00106 uint32_t size, timestamp; 00107 00108 avio_skip(pb, 1); /* one byte has been read ahead */ 00109 avio_skip(pb, 2); 00110 avio_skip(pb, 2); 00111 keyframe = avio_rl16(pb); 00112 size = avio_rl32(pb); 00113 avio_skip(pb, 4); 00114 avio_skip(pb, 4); 00115 timestamp = avio_rl32(pb); 00116 00117 if(!size || av_get_packet(pb, pkt, size) != size) 00118 return -1; 00119 00120 avio_skip(pb, 1); /* Read ahead one byte of struct size like read_header */ 00121 00122 pkt->pts = timestamp; 00123 pkt->dts = timestamp; 00124 pkt->stream_index = 0; 00125 00126 /* Some aMsn generated videos (or was it Mercury Messenger?) don't set 00127 * this bit and rely on the codec to get keyframe information */ 00128 if(keyframe&1) 00129 pkt->flags |= AV_PKT_FLAG_KEY; 00130 00131 return HEADER_SIZE + size; 00132 } 00133 00134 AVInputFormat ff_msnwc_tcp_demuxer = { 00135 .name = "msnwctcp", 00136 .long_name = NULL_IF_CONFIG_SMALL("MSN TCP Webcam stream"), 00137 .read_probe = msnwc_tcp_probe, 00138 .read_header = msnwc_tcp_read_header, 00139 .read_packet = msnwc_tcp_read_packet, 00140 };