1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * Vivo stream demuxer 3cabdff1aSopenharmony_ci * Copyright (c) 2009 Daniel Verkamp <daniel at drv.nu> 4cabdff1aSopenharmony_ci * 5cabdff1aSopenharmony_ci * This file is part of FFmpeg. 6cabdff1aSopenharmony_ci * 7cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 8cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 9cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 10cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 11cabdff1aSopenharmony_ci * 12cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 13cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 14cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15cabdff1aSopenharmony_ci * Lesser General Public License for more details. 16cabdff1aSopenharmony_ci * 17cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 18cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 19cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20cabdff1aSopenharmony_ci */ 21cabdff1aSopenharmony_ci 22cabdff1aSopenharmony_ci/** 23cabdff1aSopenharmony_ci * @file 24cabdff1aSopenharmony_ci * @brief Vivo stream demuxer 25cabdff1aSopenharmony_ci * @author Daniel Verkamp <daniel at drv.nu> 26cabdff1aSopenharmony_ci * @sa http://wiki.multimedia.cx/index.php?title=Vivo 27cabdff1aSopenharmony_ci */ 28cabdff1aSopenharmony_ci 29cabdff1aSopenharmony_ci#include "libavutil/avstring.h" 30cabdff1aSopenharmony_ci#include "libavutil/parseutils.h" 31cabdff1aSopenharmony_ci#include "avformat.h" 32cabdff1aSopenharmony_ci#include "internal.h" 33cabdff1aSopenharmony_ci 34cabdff1aSopenharmony_citypedef struct VivoContext { 35cabdff1aSopenharmony_ci int version; 36cabdff1aSopenharmony_ci 37cabdff1aSopenharmony_ci int type; 38cabdff1aSopenharmony_ci int sequence; 39cabdff1aSopenharmony_ci int length; 40cabdff1aSopenharmony_ci int duration; 41cabdff1aSopenharmony_ci 42cabdff1aSopenharmony_ci uint8_t text[1024 + 1]; 43cabdff1aSopenharmony_ci} VivoContext; 44cabdff1aSopenharmony_ci 45cabdff1aSopenharmony_cistatic int vivo_probe(const AVProbeData *p) 46cabdff1aSopenharmony_ci{ 47cabdff1aSopenharmony_ci const unsigned char *buf = p->buf; 48cabdff1aSopenharmony_ci unsigned c, length = 0; 49cabdff1aSopenharmony_ci 50cabdff1aSopenharmony_ci // stream must start with packet of type 0 and sequence number 0 51cabdff1aSopenharmony_ci if (*buf++ != 0) 52cabdff1aSopenharmony_ci return 0; 53cabdff1aSopenharmony_ci 54cabdff1aSopenharmony_ci // read at most 2 bytes of coded length 55cabdff1aSopenharmony_ci c = *buf++; 56cabdff1aSopenharmony_ci length = c & 0x7F; 57cabdff1aSopenharmony_ci if (c & 0x80) { 58cabdff1aSopenharmony_ci c = *buf++; 59cabdff1aSopenharmony_ci length = (length << 7) | (c & 0x7F); 60cabdff1aSopenharmony_ci } 61cabdff1aSopenharmony_ci if (c & 0x80 || length > 1024 || length < 21) 62cabdff1aSopenharmony_ci return 0; 63cabdff1aSopenharmony_ci 64cabdff1aSopenharmony_ci buf += 2; 65cabdff1aSopenharmony_ci if (memcmp(buf, "Version:Vivo/", 13)) 66cabdff1aSopenharmony_ci return 0; 67cabdff1aSopenharmony_ci buf += 13; 68cabdff1aSopenharmony_ci 69cabdff1aSopenharmony_ci if (*buf < '0' || *buf > '2') 70cabdff1aSopenharmony_ci return 0; 71cabdff1aSopenharmony_ci 72cabdff1aSopenharmony_ci return AVPROBE_SCORE_MAX; 73cabdff1aSopenharmony_ci} 74cabdff1aSopenharmony_ci 75cabdff1aSopenharmony_cistatic int vivo_get_packet_header(AVFormatContext *s) 76cabdff1aSopenharmony_ci{ 77cabdff1aSopenharmony_ci VivoContext *vivo = s->priv_data; 78cabdff1aSopenharmony_ci AVIOContext *pb = s->pb; 79cabdff1aSopenharmony_ci unsigned c, get_length = 0; 80cabdff1aSopenharmony_ci 81cabdff1aSopenharmony_ci if (avio_feof(pb)) 82cabdff1aSopenharmony_ci return AVERROR_EOF; 83cabdff1aSopenharmony_ci 84cabdff1aSopenharmony_ci c = avio_r8(pb); 85cabdff1aSopenharmony_ci if (c == 0x82) { 86cabdff1aSopenharmony_ci get_length = 1; 87cabdff1aSopenharmony_ci c = avio_r8(pb); 88cabdff1aSopenharmony_ci } 89cabdff1aSopenharmony_ci 90cabdff1aSopenharmony_ci vivo->type = c >> 4; 91cabdff1aSopenharmony_ci vivo->sequence = c & 0xF; 92cabdff1aSopenharmony_ci 93cabdff1aSopenharmony_ci switch (vivo->type) { 94cabdff1aSopenharmony_ci case 0: get_length = 1; break; 95cabdff1aSopenharmony_ci case 1: vivo->length = 128; break; 96cabdff1aSopenharmony_ci case 2: get_length = 1; break; 97cabdff1aSopenharmony_ci case 3: vivo->length = 40; break; 98cabdff1aSopenharmony_ci case 4: vivo->length = 24; break; 99cabdff1aSopenharmony_ci default: 100cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "unknown packet type %d\n", vivo->type); 101cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 102cabdff1aSopenharmony_ci } 103cabdff1aSopenharmony_ci 104cabdff1aSopenharmony_ci if (get_length) { 105cabdff1aSopenharmony_ci c = avio_r8(pb); 106cabdff1aSopenharmony_ci vivo->length = c & 0x7F; 107cabdff1aSopenharmony_ci if (c & 0x80) { 108cabdff1aSopenharmony_ci c = avio_r8(pb); 109cabdff1aSopenharmony_ci vivo->length = (vivo->length << 7) | (c & 0x7F); 110cabdff1aSopenharmony_ci 111cabdff1aSopenharmony_ci if (c & 0x80) { 112cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "coded length is more than two bytes\n"); 113cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 114cabdff1aSopenharmony_ci } 115cabdff1aSopenharmony_ci } 116cabdff1aSopenharmony_ci } 117cabdff1aSopenharmony_ci 118cabdff1aSopenharmony_ci return 0; 119cabdff1aSopenharmony_ci} 120cabdff1aSopenharmony_ci 121cabdff1aSopenharmony_cistatic int vivo_read_header(AVFormatContext *s) 122cabdff1aSopenharmony_ci{ 123cabdff1aSopenharmony_ci VivoContext *vivo = s->priv_data; 124cabdff1aSopenharmony_ci AVRational fps = { 0 }; 125cabdff1aSopenharmony_ci AVStream *ast, *vst; 126cabdff1aSopenharmony_ci unsigned char *line, *line_end, *key, *value; 127cabdff1aSopenharmony_ci long value_int; 128cabdff1aSopenharmony_ci int ret, value_used; 129cabdff1aSopenharmony_ci int64_t duration = 0; 130cabdff1aSopenharmony_ci char *end_value; 131cabdff1aSopenharmony_ci 132cabdff1aSopenharmony_ci vst = avformat_new_stream(s, NULL); 133cabdff1aSopenharmony_ci ast = avformat_new_stream(s, NULL); 134cabdff1aSopenharmony_ci if (!ast || !vst) 135cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 136cabdff1aSopenharmony_ci 137cabdff1aSopenharmony_ci ast->codecpar->sample_rate = 8000; 138cabdff1aSopenharmony_ci 139cabdff1aSopenharmony_ci while (1) { 140cabdff1aSopenharmony_ci if ((ret = vivo_get_packet_header(s)) < 0) 141cabdff1aSopenharmony_ci return ret; 142cabdff1aSopenharmony_ci 143cabdff1aSopenharmony_ci // done reading all text header packets? 144cabdff1aSopenharmony_ci if (vivo->sequence || vivo->type) 145cabdff1aSopenharmony_ci break; 146cabdff1aSopenharmony_ci 147cabdff1aSopenharmony_ci if (vivo->length <= 1024) { 148cabdff1aSopenharmony_ci avio_read(s->pb, vivo->text, vivo->length); 149cabdff1aSopenharmony_ci vivo->text[vivo->length] = 0; 150cabdff1aSopenharmony_ci } else { 151cabdff1aSopenharmony_ci av_log(s, AV_LOG_WARNING, "too big header, skipping\n"); 152cabdff1aSopenharmony_ci avio_skip(s->pb, vivo->length); 153cabdff1aSopenharmony_ci continue; 154cabdff1aSopenharmony_ci } 155cabdff1aSopenharmony_ci 156cabdff1aSopenharmony_ci line = vivo->text; 157cabdff1aSopenharmony_ci while (*line) { 158cabdff1aSopenharmony_ci line_end = strstr(line, "\r\n"); 159cabdff1aSopenharmony_ci if (!line_end) 160cabdff1aSopenharmony_ci break; 161cabdff1aSopenharmony_ci 162cabdff1aSopenharmony_ci *line_end = 0; 163cabdff1aSopenharmony_ci key = line; 164cabdff1aSopenharmony_ci line = line_end + 2; // skip \r\n 165cabdff1aSopenharmony_ci 166cabdff1aSopenharmony_ci if (line_end == key) // skip blank lines 167cabdff1aSopenharmony_ci continue; 168cabdff1aSopenharmony_ci 169cabdff1aSopenharmony_ci value = strchr(key, ':'); 170cabdff1aSopenharmony_ci if (!value) { 171cabdff1aSopenharmony_ci av_log(s, AV_LOG_WARNING, "missing colon in key:value pair '%s'\n", 172cabdff1aSopenharmony_ci key); 173cabdff1aSopenharmony_ci continue; 174cabdff1aSopenharmony_ci } 175cabdff1aSopenharmony_ci 176cabdff1aSopenharmony_ci *value++ = 0; 177cabdff1aSopenharmony_ci 178cabdff1aSopenharmony_ci av_log(s, AV_LOG_DEBUG, "header: '%s' = '%s'\n", key, value); 179cabdff1aSopenharmony_ci 180cabdff1aSopenharmony_ci value_int = strtol(value, &end_value, 10); 181cabdff1aSopenharmony_ci value_used = 0; 182cabdff1aSopenharmony_ci if (*end_value == 0) { // valid integer 183cabdff1aSopenharmony_ci av_log(s, AV_LOG_DEBUG, "got a valid integer (%ld)\n", value_int); 184cabdff1aSopenharmony_ci value_used = 1; 185cabdff1aSopenharmony_ci if (!strcmp(key, "Duration")) { 186cabdff1aSopenharmony_ci duration = value_int; 187cabdff1aSopenharmony_ci } else if (!strcmp(key, "Width")) { 188cabdff1aSopenharmony_ci vst->codecpar->width = value_int; 189cabdff1aSopenharmony_ci } else if (!strcmp(key, "Height")) { 190cabdff1aSopenharmony_ci vst->codecpar->height = value_int; 191cabdff1aSopenharmony_ci } else if (!strcmp(key, "TimeUnitNumerator")) { 192cabdff1aSopenharmony_ci fps.num = value_int / 1000; 193cabdff1aSopenharmony_ci } else if (!strcmp(key, "TimeUnitDenominator")) { 194cabdff1aSopenharmony_ci fps.den = value_int; 195cabdff1aSopenharmony_ci } else if (!strcmp(key, "SamplingFrequency")) { 196cabdff1aSopenharmony_ci ast->codecpar->sample_rate = value_int; 197cabdff1aSopenharmony_ci } else if (!strcmp(key, "NominalBitrate")) { 198cabdff1aSopenharmony_ci } else if (!strcmp(key, "Length")) { 199cabdff1aSopenharmony_ci // size of file 200cabdff1aSopenharmony_ci } else { 201cabdff1aSopenharmony_ci value_used = 0; 202cabdff1aSopenharmony_ci } 203cabdff1aSopenharmony_ci } 204cabdff1aSopenharmony_ci 205cabdff1aSopenharmony_ci if (!strcmp(key, "Version")) { 206cabdff1aSopenharmony_ci if (sscanf(value, "Vivo/%d.", &vivo->version) != 1) 207cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 208cabdff1aSopenharmony_ci value_used = 1; 209cabdff1aSopenharmony_ci } else if (!strcmp(key, "FPS")) { 210cabdff1aSopenharmony_ci double d; 211cabdff1aSopenharmony_ci if (av_sscanf(value, "%f", &d) != 1) 212cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 213cabdff1aSopenharmony_ci 214cabdff1aSopenharmony_ci value_used = 1; 215cabdff1aSopenharmony_ci if (!fps.num && !fps.den) 216cabdff1aSopenharmony_ci fps = av_inv_q(av_d2q(d, 10000)); 217cabdff1aSopenharmony_ci } 218cabdff1aSopenharmony_ci 219cabdff1aSopenharmony_ci if (!value_used) 220cabdff1aSopenharmony_ci av_dict_set(&s->metadata, key, value, 0); 221cabdff1aSopenharmony_ci } 222cabdff1aSopenharmony_ci } 223cabdff1aSopenharmony_ci if (!fps.num || !fps.den) 224cabdff1aSopenharmony_ci fps = (AVRational){ 1, 25 }; 225cabdff1aSopenharmony_ci 226cabdff1aSopenharmony_ci avpriv_set_pts_info(ast, 64, 1, ast->codecpar->sample_rate); 227cabdff1aSopenharmony_ci avpriv_set_pts_info(vst, 64, fps.num, fps.den); 228cabdff1aSopenharmony_ci if (duration) 229cabdff1aSopenharmony_ci s->duration = av_rescale(duration, 1000, 1); 230cabdff1aSopenharmony_ci 231cabdff1aSopenharmony_ci vst->start_time = 0; 232cabdff1aSopenharmony_ci vst->codecpar->codec_tag = 0; 233cabdff1aSopenharmony_ci vst->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; 234cabdff1aSopenharmony_ci 235cabdff1aSopenharmony_ci if (vivo->version == 1) { 236cabdff1aSopenharmony_ci vst->codecpar->codec_id = AV_CODEC_ID_H263; 237cabdff1aSopenharmony_ci ast->codecpar->codec_id = AV_CODEC_ID_G723_1; 238cabdff1aSopenharmony_ci ast->codecpar->bits_per_coded_sample = 8; 239cabdff1aSopenharmony_ci ast->codecpar->block_align = 24; 240cabdff1aSopenharmony_ci ast->codecpar->bit_rate = 6400; 241cabdff1aSopenharmony_ci } else { 242cabdff1aSopenharmony_ci ast->codecpar->codec_id = AV_CODEC_ID_SIREN; 243cabdff1aSopenharmony_ci ast->codecpar->bits_per_coded_sample = 16; 244cabdff1aSopenharmony_ci ast->codecpar->block_align = 40; 245cabdff1aSopenharmony_ci ast->codecpar->bit_rate = 6400; 246cabdff1aSopenharmony_ci vivo->duration = 320; 247cabdff1aSopenharmony_ci } 248cabdff1aSopenharmony_ci 249cabdff1aSopenharmony_ci ast->start_time = 0; 250cabdff1aSopenharmony_ci ast->codecpar->codec_tag = 0; 251cabdff1aSopenharmony_ci ast->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; 252cabdff1aSopenharmony_ci ast->codecpar->ch_layout.nb_channels = 1; 253cabdff1aSopenharmony_ci 254cabdff1aSopenharmony_ci return 0; 255cabdff1aSopenharmony_ci} 256cabdff1aSopenharmony_ci 257cabdff1aSopenharmony_cistatic int vivo_read_packet(AVFormatContext *s, AVPacket *pkt) 258cabdff1aSopenharmony_ci{ 259cabdff1aSopenharmony_ci VivoContext *vivo = s->priv_data; 260cabdff1aSopenharmony_ci AVIOContext *pb = s->pb; 261cabdff1aSopenharmony_ci unsigned old_sequence = vivo->sequence, old_type = vivo->type; 262cabdff1aSopenharmony_ci int stream_index, duration, ret = 0; 263cabdff1aSopenharmony_ci 264cabdff1aSopenharmony_cirestart: 265cabdff1aSopenharmony_ci 266cabdff1aSopenharmony_ci if (avio_feof(pb)) 267cabdff1aSopenharmony_ci return AVERROR_EOF; 268cabdff1aSopenharmony_ci 269cabdff1aSopenharmony_ci switch (vivo->type) { 270cabdff1aSopenharmony_ci case 0: 271cabdff1aSopenharmony_ci avio_skip(pb, vivo->length); 272cabdff1aSopenharmony_ci if ((ret = vivo_get_packet_header(s)) < 0) 273cabdff1aSopenharmony_ci return ret; 274cabdff1aSopenharmony_ci goto restart; 275cabdff1aSopenharmony_ci case 1: 276cabdff1aSopenharmony_ci case 2: // video 277cabdff1aSopenharmony_ci stream_index = 0; 278cabdff1aSopenharmony_ci duration = 1; 279cabdff1aSopenharmony_ci break; 280cabdff1aSopenharmony_ci case 3: 281cabdff1aSopenharmony_ci case 4: // audio 282cabdff1aSopenharmony_ci stream_index = 1; 283cabdff1aSopenharmony_ci duration = vivo->duration; 284cabdff1aSopenharmony_ci break; 285cabdff1aSopenharmony_ci default: 286cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "unknown packet type %d\n", vivo->type); 287cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 288cabdff1aSopenharmony_ci } 289cabdff1aSopenharmony_ci 290cabdff1aSopenharmony_ci if ((ret = av_get_packet(pb, pkt, vivo->length)) < 0) 291cabdff1aSopenharmony_ci return ret; 292cabdff1aSopenharmony_ci 293cabdff1aSopenharmony_ci // get next packet header 294cabdff1aSopenharmony_ci if ((ret = vivo_get_packet_header(s)) < 0) 295cabdff1aSopenharmony_ci return ret; 296cabdff1aSopenharmony_ci 297cabdff1aSopenharmony_ci while (vivo->sequence == old_sequence && 298cabdff1aSopenharmony_ci (((vivo->type - 1) >> 1) == ((old_type - 1) >> 1))) { 299cabdff1aSopenharmony_ci if (avio_feof(pb)) { 300cabdff1aSopenharmony_ci return AVERROR_EOF; 301cabdff1aSopenharmony_ci } 302cabdff1aSopenharmony_ci 303cabdff1aSopenharmony_ci if ((ret = av_append_packet(pb, pkt, vivo->length)) < 0) 304cabdff1aSopenharmony_ci return ret; 305cabdff1aSopenharmony_ci 306cabdff1aSopenharmony_ci // get next packet header 307cabdff1aSopenharmony_ci if ((ret = vivo_get_packet_header(s)) < 0) 308cabdff1aSopenharmony_ci return ret; 309cabdff1aSopenharmony_ci } 310cabdff1aSopenharmony_ci 311cabdff1aSopenharmony_ci pkt->stream_index = stream_index; 312cabdff1aSopenharmony_ci pkt->duration = duration; 313cabdff1aSopenharmony_ci 314cabdff1aSopenharmony_ci return ret; 315cabdff1aSopenharmony_ci} 316cabdff1aSopenharmony_ci 317cabdff1aSopenharmony_ciconst AVInputFormat ff_vivo_demuxer = { 318cabdff1aSopenharmony_ci .name = "vivo", 319cabdff1aSopenharmony_ci .long_name = NULL_IF_CONFIG_SMALL("Vivo"), 320cabdff1aSopenharmony_ci .priv_data_size = sizeof(VivoContext), 321cabdff1aSopenharmony_ci .read_probe = vivo_probe, 322cabdff1aSopenharmony_ci .read_header = vivo_read_header, 323cabdff1aSopenharmony_ci .read_packet = vivo_read_packet, 324cabdff1aSopenharmony_ci .extensions = "viv", 325cabdff1aSopenharmony_ci}; 326