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