static int cine_read_header(AVFormatContext *avctx) { AVIOContext *pb = avctx->pb; AVStream *st; unsigned int version, compression, offImageHeader, offSetup, offImageOffsets, biBitCount, length, CFA; int vflip; char *description; uint64_t i; st = avformat_new_stream(avctx, NULL); if (!st) return AVERROR(ENOMEM); st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; st->codecpar->codec_id = AV_CODEC_ID_RAWVIDEO; st->codecpar->codec_tag = 0; /* CINEFILEHEADER structure */ avio_skip(pb, 4); // Type, Headersize compression = avio_rl16(pb); version = avio_rl16(pb); if (version != 1) { avpriv_request_sample(avctx, "unknown version %i", version); return AVERROR_INVALIDDATA; } avio_skip(pb, 12); // FirstMovieImage, TotalImageCount, FirstImageNumber st->duration = avio_rl32(pb); offImageHeader = avio_rl32(pb); offSetup = avio_rl32(pb); offImageOffsets = avio_rl32(pb); avio_skip(pb, 8); // TriggerTime /* BITMAPINFOHEADER structure */ avio_seek(pb, offImageHeader, SEEK_SET); avio_skip(pb, 4); //biSize st->codecpar->width = avio_rl32(pb); st->codecpar->height = avio_rl32(pb); if (avio_rl16(pb) != 1) // biPlanes return AVERROR_INVALIDDATA; biBitCount = avio_rl16(pb); if (biBitCount != 8 && biBitCount != 16 && biBitCount != 24 && biBitCount != 48) { avpriv_request_sample(avctx, "unsupported biBitCount %i", biBitCount); return AVERROR_INVALIDDATA; } switch (avio_rl32(pb)) { case BMP_RGB: vflip = 0; break; case 0x100: /* BI_PACKED */ st->codecpar->codec_tag = MKTAG('B', 'I', 'T', 0); vflip = 1; break; default: avpriv_request_sample(avctx, "unknown bitmap compression"); return AVERROR_INVALIDDATA; } avio_skip(pb, 4); // biSizeImage /* parse SETUP structure */ avio_seek(pb, offSetup, SEEK_SET); avio_skip(pb, 140); // FrameRatae16 .. descriptionOld if (avio_rl16(pb) != 0x5453) return AVERROR_INVALIDDATA; length = avio_rl16(pb); if (length < 0x163C) { avpriv_request_sample(avctx, "short SETUP header"); return AVERROR_INVALIDDATA; } avio_skip(pb, 616); // Binning .. bFlipH if (!avio_rl32(pb) ^ vflip) { st->codecpar->extradata = av_strdup("BottomUp"); st->codecpar->extradata_size = 9; } avio_skip(pb, 4); // Grid avpriv_set_pts_info(st, 64, 1, avio_rl32(pb)); avio_skip(pb, 20); // Shutter .. bEnableColor set_metadata_int(&st->metadata, "camera_version", avio_rl32(pb), 0); set_metadata_int(&st->metadata, "firmware_version", avio_rl32(pb), 0); set_metadata_int(&st->metadata, "software_version", avio_rl32(pb), 0); set_metadata_int(&st->metadata, "recording_timezone", avio_rl32(pb), 0); CFA = avio_rl32(pb); set_metadata_int(&st->metadata, "brightness", avio_rl32(pb), 1); set_metadata_int(&st->metadata, "contrast", avio_rl32(pb), 1); set_metadata_int(&st->metadata, "gamma", avio_rl32(pb), 1); avio_skip(pb, 12 + 16); // Reserved1 .. AutoExpRect set_metadata_float(&st->metadata, "wbgain[0].r", av_int2float(avio_rl32(pb)), 1); set_metadata_float(&st->metadata, "wbgain[0].b", av_int2float(avio_rl32(pb)), 1); avio_skip(pb, 36); // WBGain[1].. WBView st->codecpar->bits_per_coded_sample = avio_rl32(pb); if (compression == CC_RGB) { if (biBitCount == 8) { st->codecpar->format = AV_PIX_FMT_GRAY8; } else if (biBitCount == 16) { st->codecpar->format = AV_PIX_FMT_GRAY16LE; } else if (biBitCount == 24) { st->codecpar->format = AV_PIX_FMT_BGR24; } else if (biBitCount == 48) { st->codecpar->format = AV_PIX_FMT_BGR48LE; } else { avpriv_request_sample(avctx, "unsupported biBitCount %i", biBitCount); return AVERROR_INVALIDDATA; } } else if (compression == CC_UNINT) { switch (CFA & 0xFFFFFF) { case CFA_BAYER: if (biBitCount == 8) { st->codecpar->format = AV_PIX_FMT_BAYER_GBRG8; } else if (biBitCount == 16) { st->codecpar->format = AV_PIX_FMT_BAYER_GBRG16LE; } else { avpriv_request_sample(avctx, "unsupported biBitCount %i", biBitCount); return AVERROR_INVALIDDATA; } break; case CFA_BAYERFLIP: if (biBitCount == 8) { st->codecpar->format = AV_PIX_FMT_BAYER_RGGB8; } else if (biBitCount == 16) { st->codecpar->format = AV_PIX_FMT_BAYER_RGGB16LE; } else { avpriv_request_sample(avctx, "unsupported biBitCount %i", biBitCount); return AVERROR_INVALIDDATA; } break; default: avpriv_request_sample(avctx, "unsupported Color Field Array (CFA) %i", CFA & 0xFFFFFF); return AVERROR_INVALIDDATA; } } else { //CC_LEAD avpriv_request_sample(avctx, "unsupported compression %i", compression); return AVERROR_INVALIDDATA; } avio_skip(pb, 668); // Conv8Min ... Sensor set_metadata_int(&st->metadata, "shutter_ns", avio_rl32(pb), 0); avio_skip(pb, 24); // EDRShutterNs ... ImHeightAcq #define DESCRIPTION_SIZE 4096 description = av_malloc(DESCRIPTION_SIZE + 1); if (!description) return AVERROR(ENOMEM); i = avio_get_str(pb, DESCRIPTION_SIZE, description, DESCRIPTION_SIZE + 1); if (i < DESCRIPTION_SIZE) avio_skip(pb, DESCRIPTION_SIZE - i); if (description[0]) av_dict_set(&st->metadata, "description", description, AV_DICT_DONT_STRDUP_VAL); else av_free(description); avio_skip(pb, 1176); // RisingEdge ... cmUser set_metadata_int(&st->metadata, "enable_crop", avio_rl32(pb), 1); set_metadata_int(&st->metadata, "crop_left", avio_rl32(pb), 1); set_metadata_int(&st->metadata, "crop_top", avio_rl32(pb), 1); set_metadata_int(&st->metadata, "crop_right", avio_rl32(pb), 1); set_metadata_int(&st->metadata, "crop_bottom", avio_rl32(pb), 1); /* parse image offsets */ avio_seek(pb, offImageOffsets, SEEK_SET); for (i = 0; i < st->duration; i++) av_add_index_entry(st, avio_rl64(pb), i, 0, 0, AVINDEX_KEYFRAME); return 0; }