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