📄 lqt_qtvr.c
字号:
/******************************************************************************* lqt_qtvr.c libquicktime - A library for reading and writing quicktime/avi/mp4 files. http://libquicktime.sourceforge.net Copyright (C) 2002 Heroine Virtual Ltd. Copyright (C) 2002-2007 Members of the libquicktime project. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA*******************************************************************************/ #include "lqt_private.h"#include <stdlib.h>#define LOG_DOMAIN "qtvr"/* util */static int deg2frame(quicktime_t *file, float hdeg, float vdeg){ return ((hdeg * abs(vdeg-90)) / 64800) * lqt_qtvr_get_columns(file) * lqt_qtvr_get_rows(file) * file->moov.udta.navg.loop_frames;}int lqt_qtvr_add_object_node(quicktime_t *file){ quicktime_atom_t chunk_atom; quicktime_qtatom_t root_atom, leaf_atom; quicktime_trak_t *trak; quicktime_ndhd_init(&(file->qtvr_node[0].ndhd)); trak = file->moov.trak[lqt_qtvr_get_qtvr_track(file)]; if (quicktime_track_samples(file, trak) > 0) { lqt_log(file, LQT_LOG_ERROR, LOG_DOMAIN, "lqt_qtvr_add_node only single node movies supported."); return -1; } quicktime_write_chunk_header(file, trak, &chunk_atom); quicktime_qtatom_write_container_header(file); quicktime_qtatom_write_header(file, &root_atom, "sean", 1); root_atom.child_count = 1; quicktime_qtatom_write_header(file, &leaf_atom, "ndhd", 1); quicktime_write_ndhd(file, &(file->qtvr_node[0].ndhd)); quicktime_qtatom_write_footer(file, &leaf_atom); quicktime_qtatom_write_footer(file, &root_atom); quicktime_write_chunk_footer(file, trak, 1, &chunk_atom, 1); trak->mdia.minf.stbl.stsd.table->qtvr.vrnp.children++; trak->mdia.minf.stbl.stsd.table->qtvr.vrnp.vrni->nloc.nodeType[0] = 'o'; trak->mdia.minf.stbl.stsd.table->qtvr.vrnp.vrni->nloc.nodeType[1] = 'b'; trak->mdia.minf.stbl.stsd.table->qtvr.vrnp.vrni->nloc.nodeType[2] = 'j'; trak->mdia.minf.stbl.stsd.table->qtvr.vrnp.vrni->nloc.nodeType[3] = 'e'; trak->mdia.minf.stbl.stts.table[0].sample_count = 1; /* set duration to duration of image track */ /* works with 1 too but this seems to be more correct */ trak->mdia.minf.stbl.stts.table[0].sample_duration = file->qtvr_node[0].obji.rows * file->qtvr_node[0].obji.columns; trak->tref.references[0].tracks[0] = file->moov.trak[lqt_qtvr_get_object_track(file)]->tkhd.track_id; trak = file->moov.trak[lqt_qtvr_get_object_track(file)]; quicktime_write_chunk_header(file, trak, &chunk_atom); quicktime_qtatom_write_container_header(file); quicktime_qtatom_write_header(file, &root_atom, "sean", 1); root_atom.child_count = 1; quicktime_qtatom_write_header(file, &leaf_atom, "obji", 1); leaf_atom.child_count = 0; quicktime_write_obji(file, &(file->qtvr_node[0].obji)); quicktime_qtatom_write_footer(file, &leaf_atom); quicktime_qtatom_write_footer(file, &root_atom); quicktime_write_chunk_footer(file, trak, 1, &chunk_atom, 1); trak->mdia.minf.stbl.stts.table[0].sample_count = 1; /* set duration to duration of image track */ trak->mdia.minf.stbl.stts.table[0].sample_duration = file->qtvr_node[0].obji.rows * file->qtvr_node[0].obji.columns; return 0;}int lqt_qtvr_add_panorama_node(quicktime_t *file){ quicktime_atom_t chunk_atom; quicktime_qtatom_t root_atom, leaf_atom; quicktime_trak_t *trak; quicktime_ndhd_init(&(file->qtvr_node[0].ndhd)); file->qtvr_node[0].ndhd.nodeType[0] = 'p'; file->qtvr_node[0].ndhd.nodeType[1] = 'a'; file->qtvr_node[0].ndhd.nodeType[2] = 'n'; file->qtvr_node[0].ndhd.nodeType[3] = 'o'; file->qtvr_node[0].pdat.imageSizeX = quicktime_video_width(file, 0); // could be a different track file->qtvr_node[0].pdat.imageSizeY = quicktime_video_height(file, 0) * file->qtvr_node[0].pdat.imageNumFramesY; trak = file->moov.trak[lqt_qtvr_get_qtvr_track(file)]; if (quicktime_track_samples(file, trak) > 0) { lqt_log(file, LQT_LOG_ERROR, LOG_DOMAIN, "lqt_qtvr_add_node only single node movies supported."); return -1; } quicktime_write_chunk_header(file, trak, &chunk_atom); quicktime_qtatom_write_container_header(file); quicktime_qtatom_write_header(file, &root_atom, "sean", 1); root_atom.child_count = 1; quicktime_qtatom_write_header(file, &leaf_atom, "ndhd", 1); quicktime_write_ndhd(file, &(file->qtvr_node[0].ndhd)); quicktime_qtatom_write_footer(file, &leaf_atom); quicktime_qtatom_write_footer(file, &root_atom); quicktime_write_chunk_footer(file, trak, 1, &chunk_atom, 1); trak->mdia.minf.stbl.stsd.table->qtvr.vrnp.children++; trak->mdia.minf.stbl.stsd.table->qtvr.vrnp.vrni->nloc.nodeType[0] = 'p'; trak->mdia.minf.stbl.stsd.table->qtvr.vrnp.vrni->nloc.nodeType[1] = 'a'; trak->mdia.minf.stbl.stsd.table->qtvr.vrnp.vrni->nloc.nodeType[2] = 'n'; trak->mdia.minf.stbl.stsd.table->qtvr.vrnp.vrni->nloc.nodeType[3] = 'o'; trak->mdia.minf.stbl.stts.table[0].sample_count = 1; /* set duration to duration of image track */ /* works with 1 too but this seems more correct */ trak->mdia.minf.stbl.stts.table[0].sample_duration = file->qtvr_node[0].pdat.imageNumFramesX * file->qtvr_node[0].pdat.imageNumFramesX; trak->tref.references[0].tracks[0] = file->moov.trak[lqt_qtvr_get_panorama_track(file)]->tkhd.track_id; trak = file->moov.trak[lqt_qtvr_get_panorama_track(file)]; quicktime_write_chunk_header(file, trak, &chunk_atom); quicktime_qtatom_write_container_header(file); quicktime_qtatom_write_header(file, &root_atom, "sean", 1); root_atom.child_count = 1; quicktime_qtatom_write_header(file, &leaf_atom, "pdat", 1); leaf_atom.child_count = 0; quicktime_write_pdat(file, &(file->qtvr_node[0].pdat)); quicktime_qtatom_write_footer(file, &leaf_atom); quicktime_qtatom_write_footer(file, &root_atom); quicktime_write_chunk_footer(file, trak, 1, &chunk_atom, 1); trak->mdia.minf.stbl.stts.table[0].sample_count = 1; /* set duration to duration of image track */ trak->mdia.minf.stbl.stts.table[0].sample_duration = file->qtvr_node[0].pdat.imageNumFramesX * file->qtvr_node[0].pdat.imageNumFramesX; return 0;}/* type of file */int lqt_is_qtvr(quicktime_t *file){ if (file->moov.udta.is_qtvr) { if (quicktime_match_32(file->moov.udta.ctyp, "stna") || (lqt_qtvr_get_object_track(file) >= 0)) return QTVR_OBJ; if (quicktime_match_32(file->moov.udta.ctyp, "STpn") || (lqt_qtvr_get_panorama_track(file) >= 0)) return QTVR_PAN; } return 0;}/* type of qtvr to write */int lqt_qtvr_set_type(quicktime_t *file, int type, int width, int height, int duration, int time_scale, int scene_track){ quicktime_trak_t *trak; if (time_scale < 1 || duration < 1 || scene_track >= file->total_vtracks || scene_track < 0) return -1; if (type == QTVR_OBJ) { file->moov.udta.ctyp[0] = 'q'; file->moov.udta.ctyp[1] = 't'; file->moov.udta.ctyp[2] = 'v'; file->moov.udta.ctyp[3] = 'r'; file->moov.udta.is_qtvr = 1; trak = quicktime_add_track(file); quicktime_trak_init_qtvr(file, trak, QTVR_OBJ, width, height, duration, time_scale); quicktime_obji_init(&(file->qtvr_node[0].obji)); file->qtvr_node[0].obji.viewDuration = duration; trak = quicktime_add_track(file); quicktime_trak_init_qtvr(file, trak, QTVR_QTVR_OBJ, width, height, duration, time_scale); lqt_qtvr_set_display_width(file, width); lqt_qtvr_set_display_height(file, height); lqt_qtvr_set_image_track(file, scene_track); return 0; } if (type == QTVR_PAN) { file->moov.udta.ctyp[0] = 'q'; file->moov.udta.ctyp[1] = 't'; file->moov.udta.ctyp[2] = 'v'; file->moov.udta.ctyp[3] = 'r'; file->moov.udta.is_qtvr = 1; trak = quicktime_add_track(file); quicktime_trak_init_qtvr(file, trak, QTVR_PAN, width, height, duration, time_scale); quicktime_pdat_init(&(file->qtvr_node[0].pdat)); trak = quicktime_add_track(file); quicktime_trak_init_qtvr(file, trak, QTVR_QTVR_PAN, width, height, duration, time_scale); /* set initial scene track*/ lqt_qtvr_set_image_track(file, scene_track); return 0; } file->moov.udta.is_qtvr = 0; return -1;}/* Number of frames in loop */int lqt_qtvr_get_loop_frames(quicktime_t *file){ if (lqt_qtvr_get_object_track(file) >= 0) { return file->qtvr_node[0].obji.viewDuration / file->moov.trak[lqt_track_from_id(file, lqt_qtvr_get_image_track(file))]->mdia.minf.stbl.stts.table[0].sample_duration; } else { return file->moov.udta.navg.loop_frames; }}/* Number of rows */int lqt_qtvr_get_rows(quicktime_t *file){ if (lqt_is_qtvr(file) == QTVR_OBJ) { if (lqt_qtvr_get_object_track(file) >= 0) { return file->qtvr_node[0].obji.rows; } else { return file->moov.udta.navg.rows; } } else if (lqt_is_qtvr(file) == QTVR_PAN) { if (lqt_qtvr_get_qtvr_track(file) >= 0) { if (lqt_qtvr_get_panotype(file) == QTVR_PANO_HORZ) { return file->qtvr_node[0].pdat.imageNumFramesY; } else { return file->qtvr_node[0].pdat.imageNumFramesX; } } else { return file->moov.trak[lqt_qtvr_get_panorama_track(file)]->mdia.minf.stbl.stsd.table->pano.SNumFramesHeight; } } return -1;}/* Number of columns */int lqt_qtvr_get_columns(quicktime_t *file){ if (lqt_is_qtvr(file) == QTVR_OBJ) { if (lqt_qtvr_get_object_track(file) >= 0) { return file->qtvr_node[0].obji.columns; } else { return file->moov.udta.navg.columns; } } else if (lqt_is_qtvr(file) == QTVR_PAN) { if (lqt_qtvr_get_qtvr_track(file) >= 0) { if (lqt_qtvr_get_panotype(file) == QTVR_PANO_HORZ) { return file->qtvr_node[0].pdat.imageNumFramesX; } else { return file->qtvr_node[0].pdat.imageNumFramesY; } } else { return file->moov.trak[lqt_qtvr_get_panorama_track(file)]->mdia.minf.stbl.stsd.table->pano.SNumFramesWidth; } } return -1;}/* pan (H) */void lqt_qtvr_get_pan(quicktime_t *file, float *minpan, float *maxpan, float *defpan){ if (lqt_qtvr_get_object_track(file) >= 0) { if (minpan != NULL ) *minpan = file->qtvr_node[0].obji.minPan; if (maxpan != NULL ) *maxpan = file->qtvr_node[0].obji.maxPan; if (defpan != NULL ) *maxpan = file->qtvr_node[0].obji.defaultPan; } else { if (minpan != NULL ) *minpan = file->moov.udta.navg.startHPan; if (maxpan != NULL ) *maxpan = file->moov.udta.navg.endHPan; if (defpan != NULL ) *defpan = file->moov.udta.navg.initialHPan; }}void lqt_qtvr_set_pan(quicktime_t *file, float minpan, float maxpan, float defpan){ if (lqt_qtvr_get_object_track(file) >= 0) { file->qtvr_node[0].obji.minPan = minpan; file->qtvr_node[0].obji.maxPan = maxpan; file->qtvr_node[0].obji.defaultPan = defpan; } else { file->moov.udta.navg.startHPan = minpan; file->moov.udta.navg.endHPan = maxpan; file->moov.udta.navg.initialHPan = defpan; }}/* tilt (V) */void lqt_qtvr_get_tilt(quicktime_t *file, float *mintilt, float *maxtilt, float *deftilt){ if (lqt_qtvr_get_object_track(file) >= 0) { if (mintilt != NULL ) *mintilt = file->qtvr_node[0].obji.minTilt; if (maxtilt != NULL ) *maxtilt = file->qtvr_node[0].obji.maxTilt; if (deftilt != NULL ) *maxtilt = file->qtvr_node[0].obji.defaultTilt; } else { if (mintilt != NULL ) *mintilt = file->moov.udta.navg.startVPan; if (maxtilt != NULL ) *maxtilt = file->moov.udta.navg.endVPan; if (deftilt != NULL ) *deftilt = file->moov.udta.navg.initialVPan; }}void lqt_qtvr_set_tilt(quicktime_t *file, float mintilt, float maxtilt, float deftilt){ if (lqt_qtvr_get_object_track(file) >= 0) { file->qtvr_node[0].obji.minTilt = mintilt; file->qtvr_node[0].obji.maxTilt = maxtilt;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -