1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * IFV demuxer 3cabdff1aSopenharmony_ci * 4cabdff1aSopenharmony_ci * Copyright (c) 2019 Swaraj Hota 5cabdff1aSopenharmony_ci * 6cabdff1aSopenharmony_ci * This file is part of FFmpeg. 7cabdff1aSopenharmony_ci * 8cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 9cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 10cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 11cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 12cabdff1aSopenharmony_ci * 13cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 14cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 15cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16cabdff1aSopenharmony_ci * Lesser General Public License for more details. 17cabdff1aSopenharmony_ci * 18cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 19cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 20cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21cabdff1aSopenharmony_ci */ 22cabdff1aSopenharmony_ci 23cabdff1aSopenharmony_ci#include "libavutil/channel_layout.h" 24cabdff1aSopenharmony_ci#include "avformat.h" 25cabdff1aSopenharmony_ci#include "internal.h" 26cabdff1aSopenharmony_ci#include "avio_internal.h" 27cabdff1aSopenharmony_ci 28cabdff1aSopenharmony_citypedef struct IFVContext { 29cabdff1aSopenharmony_ci uint32_t next_video_index; 30cabdff1aSopenharmony_ci uint32_t next_audio_index; 31cabdff1aSopenharmony_ci uint32_t total_vframes; 32cabdff1aSopenharmony_ci uint32_t total_aframes; 33cabdff1aSopenharmony_ci 34cabdff1aSopenharmony_ci int width, height; 35cabdff1aSopenharmony_ci int is_audio_present; 36cabdff1aSopenharmony_ci int sample_rate; 37cabdff1aSopenharmony_ci 38cabdff1aSopenharmony_ci int video_stream_index; 39cabdff1aSopenharmony_ci int audio_stream_index; 40cabdff1aSopenharmony_ci} IFVContext; 41cabdff1aSopenharmony_ci 42cabdff1aSopenharmony_cistatic int ifv_probe(const AVProbeData *p) 43cabdff1aSopenharmony_ci{ 44cabdff1aSopenharmony_ci static const uint8_t ifv_magic[] = {0x11, 0xd2, 0xd3, 0xab, 0xba, 0xa9, 45cabdff1aSopenharmony_ci 0xcf, 0x11, 0x8e, 0xe6, 0x00, 0xc0, 0x0c, 0x20, 0x53, 0x65, 0x44}; 46cabdff1aSopenharmony_ci 47cabdff1aSopenharmony_ci if (!memcmp(p->buf, ifv_magic, sizeof(ifv_magic))) 48cabdff1aSopenharmony_ci return AVPROBE_SCORE_MAX; 49cabdff1aSopenharmony_ci 50cabdff1aSopenharmony_ci return 0; 51cabdff1aSopenharmony_ci} 52cabdff1aSopenharmony_ci 53cabdff1aSopenharmony_cistatic int read_index(AVFormatContext *s, 54cabdff1aSopenharmony_ci enum AVMediaType frame_type, 55cabdff1aSopenharmony_ci uint32_t start_index) 56cabdff1aSopenharmony_ci{ 57cabdff1aSopenharmony_ci IFVContext *ifv = s->priv_data; 58cabdff1aSopenharmony_ci AVStream *st; 59cabdff1aSopenharmony_ci int64_t pos, size, timestamp; 60cabdff1aSopenharmony_ci uint32_t end_index, i; 61cabdff1aSopenharmony_ci int ret; 62cabdff1aSopenharmony_ci 63cabdff1aSopenharmony_ci if (frame_type == AVMEDIA_TYPE_VIDEO) { 64cabdff1aSopenharmony_ci end_index = ifv->total_vframes; 65cabdff1aSopenharmony_ci st = s->streams[ifv->video_stream_index]; 66cabdff1aSopenharmony_ci } else { 67cabdff1aSopenharmony_ci end_index = ifv->total_aframes; 68cabdff1aSopenharmony_ci st = s->streams[ifv->audio_stream_index]; 69cabdff1aSopenharmony_ci } 70cabdff1aSopenharmony_ci 71cabdff1aSopenharmony_ci for (i = start_index; i < end_index; i++) { 72cabdff1aSopenharmony_ci if (avio_feof(s->pb)) 73cabdff1aSopenharmony_ci return AVERROR_EOF; 74cabdff1aSopenharmony_ci pos = avio_rl32(s->pb); 75cabdff1aSopenharmony_ci size = avio_rl32(s->pb); 76cabdff1aSopenharmony_ci 77cabdff1aSopenharmony_ci avio_skip(s->pb, 8); 78cabdff1aSopenharmony_ci timestamp = avio_rl32(s->pb); 79cabdff1aSopenharmony_ci 80cabdff1aSopenharmony_ci ret = av_add_index_entry(st, pos, timestamp, size, 0, 0); 81cabdff1aSopenharmony_ci if (ret < 0) 82cabdff1aSopenharmony_ci return ret; 83cabdff1aSopenharmony_ci 84cabdff1aSopenharmony_ci avio_skip(s->pb, frame_type == AVMEDIA_TYPE_VIDEO ? 8: 4); 85cabdff1aSopenharmony_ci } 86cabdff1aSopenharmony_ci 87cabdff1aSopenharmony_ci return 0; 88cabdff1aSopenharmony_ci} 89cabdff1aSopenharmony_ci 90cabdff1aSopenharmony_cistatic int parse_header(AVFormatContext *s) 91cabdff1aSopenharmony_ci{ 92cabdff1aSopenharmony_ci IFVContext *ifv = s->priv_data; 93cabdff1aSopenharmony_ci uint32_t aud_magic; 94cabdff1aSopenharmony_ci uint32_t vid_magic; 95cabdff1aSopenharmony_ci 96cabdff1aSopenharmony_ci avio_skip(s->pb, 0x34); 97cabdff1aSopenharmony_ci avpriv_dict_set_timestamp(&s->metadata, "creation_time", avio_rl32(s->pb) * 1000000LL); 98cabdff1aSopenharmony_ci avio_skip(s->pb, 0x24); 99cabdff1aSopenharmony_ci 100cabdff1aSopenharmony_ci ifv->width = avio_rl16(s->pb); 101cabdff1aSopenharmony_ci ifv->height = avio_rl16(s->pb); 102cabdff1aSopenharmony_ci 103cabdff1aSopenharmony_ci avio_skip(s->pb, 0x8); 104cabdff1aSopenharmony_ci vid_magic = avio_rl32(s->pb); 105cabdff1aSopenharmony_ci 106cabdff1aSopenharmony_ci if (vid_magic != MKTAG('H','2','6','4')) 107cabdff1aSopenharmony_ci avpriv_request_sample(s, "Unknown video codec %x", vid_magic); 108cabdff1aSopenharmony_ci 109cabdff1aSopenharmony_ci avio_skip(s->pb, 0x2c); 110cabdff1aSopenharmony_ci ifv->sample_rate = avio_rl32(s->pb); 111cabdff1aSopenharmony_ci aud_magic = avio_rl32(s->pb); 112cabdff1aSopenharmony_ci 113cabdff1aSopenharmony_ci if (aud_magic == MKTAG('G','R','A','W')) { 114cabdff1aSopenharmony_ci ifv->is_audio_present = 1; 115cabdff1aSopenharmony_ci } else if (aud_magic == MKTAG('P','C','M','U')) { 116cabdff1aSopenharmony_ci ifv->is_audio_present = 0; 117cabdff1aSopenharmony_ci } else { 118cabdff1aSopenharmony_ci avpriv_request_sample(s, "Unknown audio codec %x", aud_magic); 119cabdff1aSopenharmony_ci } 120cabdff1aSopenharmony_ci 121cabdff1aSopenharmony_ci avio_skip(s->pb, 0x44); 122cabdff1aSopenharmony_ci ifv->total_vframes = avio_rl32(s->pb); 123cabdff1aSopenharmony_ci ifv->total_aframes = avio_rl32(s->pb); 124cabdff1aSopenharmony_ci 125cabdff1aSopenharmony_ci return 0; 126cabdff1aSopenharmony_ci} 127cabdff1aSopenharmony_ci 128cabdff1aSopenharmony_cistatic int ifv_read_header(AVFormatContext *s) 129cabdff1aSopenharmony_ci{ 130cabdff1aSopenharmony_ci IFVContext *ifv = s->priv_data; 131cabdff1aSopenharmony_ci AVStream *st; 132cabdff1aSopenharmony_ci int ret; 133cabdff1aSopenharmony_ci 134cabdff1aSopenharmony_ci ret = parse_header(s); 135cabdff1aSopenharmony_ci if (ret < 0) 136cabdff1aSopenharmony_ci return ret; 137cabdff1aSopenharmony_ci 138cabdff1aSopenharmony_ci st = avformat_new_stream(s, NULL); 139cabdff1aSopenharmony_ci if (!st) 140cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 141cabdff1aSopenharmony_ci 142cabdff1aSopenharmony_ci st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; 143cabdff1aSopenharmony_ci st->codecpar->codec_id = AV_CODEC_ID_H264; 144cabdff1aSopenharmony_ci st->codecpar->width = ifv->width; 145cabdff1aSopenharmony_ci st->codecpar->height = ifv->height; 146cabdff1aSopenharmony_ci st->start_time = 0; 147cabdff1aSopenharmony_ci ifv->video_stream_index = st->index; 148cabdff1aSopenharmony_ci 149cabdff1aSopenharmony_ci avpriv_set_pts_info(st, 32, 1, 1000); 150cabdff1aSopenharmony_ci 151cabdff1aSopenharmony_ci if (ifv->is_audio_present) { 152cabdff1aSopenharmony_ci st = avformat_new_stream(s, NULL); 153cabdff1aSopenharmony_ci if (!st) 154cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 155cabdff1aSopenharmony_ci 156cabdff1aSopenharmony_ci st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; 157cabdff1aSopenharmony_ci st->codecpar->codec_id = AV_CODEC_ID_PCM_S16LE; 158cabdff1aSopenharmony_ci st->codecpar->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO; 159cabdff1aSopenharmony_ci st->codecpar->sample_rate = ifv->sample_rate; 160cabdff1aSopenharmony_ci ifv->audio_stream_index = st->index; 161cabdff1aSopenharmony_ci 162cabdff1aSopenharmony_ci avpriv_set_pts_info(st, 32, 1, 1000); 163cabdff1aSopenharmony_ci } 164cabdff1aSopenharmony_ci 165cabdff1aSopenharmony_ci /*read video index*/ 166cabdff1aSopenharmony_ci avio_seek(s->pb, 0xf8, SEEK_SET); 167cabdff1aSopenharmony_ci 168cabdff1aSopenharmony_ci ret = read_index(s, AVMEDIA_TYPE_VIDEO, 0); 169cabdff1aSopenharmony_ci if (ret < 0) 170cabdff1aSopenharmony_ci return ret; 171cabdff1aSopenharmony_ci 172cabdff1aSopenharmony_ci if (ifv->is_audio_present) { 173cabdff1aSopenharmony_ci /*read audio index*/ 174cabdff1aSopenharmony_ci avio_seek(s->pb, 0x14918, SEEK_SET); 175cabdff1aSopenharmony_ci 176cabdff1aSopenharmony_ci ret = read_index(s, AVMEDIA_TYPE_AUDIO, 0); 177cabdff1aSopenharmony_ci if (ret < 0) 178cabdff1aSopenharmony_ci return ret; 179cabdff1aSopenharmony_ci } 180cabdff1aSopenharmony_ci 181cabdff1aSopenharmony_ci ifv->next_video_index = 0; 182cabdff1aSopenharmony_ci ifv->next_audio_index = 0; 183cabdff1aSopenharmony_ci 184cabdff1aSopenharmony_ci return 0; 185cabdff1aSopenharmony_ci} 186cabdff1aSopenharmony_ci 187cabdff1aSopenharmony_cistatic int ifv_read_packet(AVFormatContext *s, AVPacket *pkt) 188cabdff1aSopenharmony_ci{ 189cabdff1aSopenharmony_ci IFVContext *ifv = s->priv_data; 190cabdff1aSopenharmony_ci AVIndexEntry *ev, *ea, *e_next; 191cabdff1aSopenharmony_ci int ret; 192cabdff1aSopenharmony_ci 193cabdff1aSopenharmony_ci ev = ea = e_next = NULL; 194cabdff1aSopenharmony_ci 195cabdff1aSopenharmony_ci if (ifv->next_video_index < ifv->total_vframes) { 196cabdff1aSopenharmony_ci AVStream *const st = s->streams[ifv->video_stream_index]; 197cabdff1aSopenharmony_ci FFStream *const sti = ffstream(st); 198cabdff1aSopenharmony_ci 199cabdff1aSopenharmony_ci if (ifv->next_video_index < sti->nb_index_entries) 200cabdff1aSopenharmony_ci e_next = ev = &sti->index_entries[ifv->next_video_index]; 201cabdff1aSopenharmony_ci } 202cabdff1aSopenharmony_ci 203cabdff1aSopenharmony_ci if (ifv->is_audio_present && 204cabdff1aSopenharmony_ci ifv->next_audio_index < ifv->total_aframes) { 205cabdff1aSopenharmony_ci AVStream *const st = s->streams[ifv->audio_stream_index]; 206cabdff1aSopenharmony_ci FFStream *const sti = ffstream(st); 207cabdff1aSopenharmony_ci 208cabdff1aSopenharmony_ci if (ifv->next_audio_index < sti->nb_index_entries) { 209cabdff1aSopenharmony_ci ea = &sti->index_entries[ifv->next_audio_index]; 210cabdff1aSopenharmony_ci if (!ev || ea->timestamp < ev->timestamp) 211cabdff1aSopenharmony_ci e_next = ea; 212cabdff1aSopenharmony_ci } 213cabdff1aSopenharmony_ci } 214cabdff1aSopenharmony_ci 215cabdff1aSopenharmony_ci if (!ev) { 216cabdff1aSopenharmony_ci uint64_t vframes, aframes; 217cabdff1aSopenharmony_ci if (ifv->is_audio_present && !ea) { 218cabdff1aSopenharmony_ci /*read new video and audio indexes*/ 219cabdff1aSopenharmony_ci 220cabdff1aSopenharmony_ci ifv->next_video_index = ifv->total_vframes; 221cabdff1aSopenharmony_ci ifv->next_audio_index = ifv->total_aframes; 222cabdff1aSopenharmony_ci 223cabdff1aSopenharmony_ci avio_skip(s->pb, 0x1c); 224cabdff1aSopenharmony_ci vframes = ifv->total_vframes + (uint64_t)avio_rl32(s->pb); 225cabdff1aSopenharmony_ci aframes = ifv->total_aframes + (uint64_t)avio_rl32(s->pb); 226cabdff1aSopenharmony_ci if (vframes > INT_MAX || aframes > INT_MAX) 227cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 228cabdff1aSopenharmony_ci ifv->total_vframes = vframes; 229cabdff1aSopenharmony_ci ifv->total_aframes = aframes; 230cabdff1aSopenharmony_ci avio_skip(s->pb, 0xc); 231cabdff1aSopenharmony_ci 232cabdff1aSopenharmony_ci if (avio_feof(s->pb)) 233cabdff1aSopenharmony_ci return AVERROR_EOF; 234cabdff1aSopenharmony_ci 235cabdff1aSopenharmony_ci ret = read_index(s, AVMEDIA_TYPE_VIDEO, ifv->next_video_index); 236cabdff1aSopenharmony_ci if (ret < 0) 237cabdff1aSopenharmony_ci return ret; 238cabdff1aSopenharmony_ci 239cabdff1aSopenharmony_ci ret = read_index(s, AVMEDIA_TYPE_AUDIO, ifv->next_audio_index); 240cabdff1aSopenharmony_ci if (ret < 0) 241cabdff1aSopenharmony_ci return ret; 242cabdff1aSopenharmony_ci 243cabdff1aSopenharmony_ci return 0; 244cabdff1aSopenharmony_ci 245cabdff1aSopenharmony_ci } else if (!ifv->is_audio_present) { 246cabdff1aSopenharmony_ci /*read new video index*/ 247cabdff1aSopenharmony_ci 248cabdff1aSopenharmony_ci ifv->next_video_index = ifv->total_vframes; 249cabdff1aSopenharmony_ci 250cabdff1aSopenharmony_ci avio_skip(s->pb, 0x1c); 251cabdff1aSopenharmony_ci vframes = ifv->total_vframes + (uint64_t)avio_rl32(s->pb); 252cabdff1aSopenharmony_ci if (vframes > INT_MAX) 253cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 254cabdff1aSopenharmony_ci ifv->total_vframes = vframes; 255cabdff1aSopenharmony_ci avio_skip(s->pb, 0x10); 256cabdff1aSopenharmony_ci 257cabdff1aSopenharmony_ci if (avio_feof(s->pb)) 258cabdff1aSopenharmony_ci return AVERROR_EOF; 259cabdff1aSopenharmony_ci 260cabdff1aSopenharmony_ci ret = read_index(s, AVMEDIA_TYPE_VIDEO, ifv->next_video_index); 261cabdff1aSopenharmony_ci if (ret < 0) 262cabdff1aSopenharmony_ci return ret; 263cabdff1aSopenharmony_ci 264cabdff1aSopenharmony_ci return 0; 265cabdff1aSopenharmony_ci } 266cabdff1aSopenharmony_ci } 267cabdff1aSopenharmony_ci 268cabdff1aSopenharmony_ci if (!e_next) return AVERROR_EOF; 269cabdff1aSopenharmony_ci 270cabdff1aSopenharmony_ci avio_seek(s->pb, e_next->pos, SEEK_SET); 271cabdff1aSopenharmony_ci ret = av_get_packet(s->pb, pkt, e_next->size); 272cabdff1aSopenharmony_ci if (ret < 0) 273cabdff1aSopenharmony_ci return ret; 274cabdff1aSopenharmony_ci 275cabdff1aSopenharmony_ci if (e_next == ev) { 276cabdff1aSopenharmony_ci ifv->next_video_index++; 277cabdff1aSopenharmony_ci pkt->stream_index = ifv->video_stream_index; 278cabdff1aSopenharmony_ci } else { 279cabdff1aSopenharmony_ci ifv->next_audio_index++; 280cabdff1aSopenharmony_ci pkt->stream_index = ifv->audio_stream_index; 281cabdff1aSopenharmony_ci } 282cabdff1aSopenharmony_ci 283cabdff1aSopenharmony_ci pkt->pts = e_next->timestamp; 284cabdff1aSopenharmony_ci pkt->pos = e_next->pos; 285cabdff1aSopenharmony_ci 286cabdff1aSopenharmony_ci return 0; 287cabdff1aSopenharmony_ci} 288cabdff1aSopenharmony_ci 289cabdff1aSopenharmony_cistatic int ifv_read_seek(AVFormatContext *s, int stream_index, int64_t ts, int flags) 290cabdff1aSopenharmony_ci{ 291cabdff1aSopenharmony_ci IFVContext *ifv = s->priv_data; 292cabdff1aSopenharmony_ci 293cabdff1aSopenharmony_ci for (unsigned i = 0; i < s->nb_streams; i++) { 294cabdff1aSopenharmony_ci int index = av_index_search_timestamp(s->streams[i], ts, AVSEEK_FLAG_ANY); 295cabdff1aSopenharmony_ci if (index < 0) { 296cabdff1aSopenharmony_ci ifv->next_video_index = ifv->total_vframes - 1; 297cabdff1aSopenharmony_ci ifv->next_audio_index = ifv->total_aframes - 1; 298cabdff1aSopenharmony_ci return 0; 299cabdff1aSopenharmony_ci } 300cabdff1aSopenharmony_ci 301cabdff1aSopenharmony_ci if (i == ifv->video_stream_index) { 302cabdff1aSopenharmony_ci ifv->next_video_index = index; 303cabdff1aSopenharmony_ci } else { 304cabdff1aSopenharmony_ci ifv->next_audio_index = index; 305cabdff1aSopenharmony_ci } 306cabdff1aSopenharmony_ci } 307cabdff1aSopenharmony_ci 308cabdff1aSopenharmony_ci return 0; 309cabdff1aSopenharmony_ci} 310cabdff1aSopenharmony_ci 311cabdff1aSopenharmony_ciconst AVInputFormat ff_ifv_demuxer = { 312cabdff1aSopenharmony_ci .name = "ifv", 313cabdff1aSopenharmony_ci .long_name = NULL_IF_CONFIG_SMALL("IFV CCTV DVR"), 314cabdff1aSopenharmony_ci .priv_data_size = sizeof(IFVContext), 315cabdff1aSopenharmony_ci .extensions = "ifv", 316cabdff1aSopenharmony_ci .read_probe = ifv_probe, 317cabdff1aSopenharmony_ci .read_header = ifv_read_header, 318cabdff1aSopenharmony_ci .read_packet = ifv_read_packet, 319cabdff1aSopenharmony_ci .read_seek = ifv_read_seek, 320cabdff1aSopenharmony_ci}; 321