Commit c4ada33f authored by Mikhail Karpenko's avatar Mikhail Karpenko

Update doxygen documentation

parent cb60ae2d
/** @file camogm_jpeg.c /** @file camogm_jpeg.c
* @brief Provides writing to series of individual JPEG files for camogm * @brief Provides writing to series of individual JPEG files for @e camogm
* @copyright Copyright (C) 2016 Elphel, Inc. * @copyright Copyright (C) 2016 Elphel, Inc.
* *
* @par <b>License</b> * @par <b>License</b>
......
/** @file camogm_jpeg.h /** @file camogm_jpeg.h
* @brief Provides writing to series of individual JPEG files for camogm * @brief Provides writing to series of individual JPEG files for @e camogm
* @copyright Copyright (C) 2016 Elphel, Inc. * @copyright Copyright (C) 2016 Elphel, Inc.
* *
* @par <b>License</b> * @par <b>License</b>
......
/*!*************************************************************************** /** @file camogm_kml.c
*! FILE NAME : camogm_kml.c * @brief Provides writing to series of individual KML files for @e camogm
*! DESCRIPTION: Provides writing to series of individual JPEG files for camogm * @copyright Copyright (C) 2016 Elphel, Inc.
*! Copyright (C) 2007 Elphel, Inc. *
*! -----------------------------------------------------------------------------** * @par <b>License</b>
*! This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
*! it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
*! the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
*! (at your option) any later version. * (at your option) any later version.
*! * This program is distributed in the hope that it will be useful,
*! This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of
*! but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
*! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details.
*! GNU General Public License for more details. * You should have received a copy of the GNU General Public License
*! * along with this program. If not, see <http://www.gnu.org/licenses/>.
*! You should have received a copy of the GNU General Public License
*! along with this program. If not, see <http://www.gnu.org/licenses/>.
*! -----------------------------------------------------------------------------**
*!
*! $Log: camogm_kml.c,v $
*! Revision 1.3 2011/01/03 22:00:29 elphel
*! fixed tilt generation
*!
*! Revision 1.2 2009/02/25 17:50:02 spectr_rain
*! removed deprecated dependency
*!
*! Revision 1.1.1.1 2008/11/27 20:04:01 elphel
*!
*!
*! Revision 1.2 2008/04/13 21:05:20 elphel
*! Fixing KML generation
*!
*! Revision 1.1 2008/04/11 23:06:52 elphel
*! files to handle KML generation
*!
*!
*/ */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <fcntl.h> #include <fcntl.h>
...@@ -48,45 +28,32 @@ ...@@ -48,45 +28,32 @@
const char ExifDirFileName[] = "/dev/exif_metadir"; const char ExifDirFileName[] = "/dev/exif_metadir";
//! may add something - called first time format is changed to this one (only once) recording is stopped /**
* @brief Called when format is changed to MOV (only once) and recording is stopped
*/
int camogm_init_kml(void) int camogm_init_kml(void)
{ {
return 0; return 0;
} }
void camogm_free_kml(void) void camogm_free_kml(void)
{ {
} }
/*
int camogm_start_mov(void) {
//! allocate memory for the frame index table
if (!((state->frame_lengths=malloc(4*state->max_frames)))) return -CAMOGM_FRAME_MALLOC ;
//! open file for writing
sprintf(state->path,"%s%010ld_%06ld.mov",state->path_prefix,state->frame_params.timestamp_sec,state->frame_params.timestamp_usec);
if (((state->ivf=open(state->path,O_RDWR | O_CREAT, 0777)))<0){
D0(fprintf (debug_file, "Error opening %s for writing, returned %d, errno=%d\n", state->path,state->ivf,errno));
return -CAMOGM_FRAME_FILE_ERR;
}
//!skip header (plus extra)
//! Quicktime (and else?) - frame data start (0xff 0xd8...)
state->frame_data_start=QUICKTIME_MIN_HEADER+16+ 4*(state->max_frames)+ ( 4*(state->max_frames))/(state->frames_per_chunk); // 8 bytes for "skip" tag
lseek(state->ivf, state->frame_data_start, SEEK_SET);
return 0;
}
/**
* @brief Start KML recording
* @param[in] state a pointer to a structure containing current state
* @return 0 if recording started successfully and negative error code otherwise
*/ */
int camogm_start_kml(camogm_state *state) int camogm_start_kml(camogm_state *state)
{ {
// struct exif_dir_table_t kml_exif[ExifKmlNumber] ; //! store locations of the fields needed for KML generations in the Exif block // Re-read directory table and rebuild state->kml_exif when starting each file
///exif_metadir
/// state->kml_exif[i]
/// Re-read directory table and rebuild state->kml_exif when starting each file
struct exif_dir_table_t dir_table_entry; struct exif_dir_table_t dir_table_entry;
int fd_ExifDir; int fd_ExifDir;
int indx; int indx;
for (indx = 0; indx < ExifKmlNumber; indx++) state->kml_exif[indx].ltag = 0; for (indx = 0; indx < ExifKmlNumber; indx++) state->kml_exif[indx].ltag = 0;
//! open Exif header directory file // open Exif header directory file
fd_ExifDir = open(ExifDirFileName, O_RDONLY); fd_ExifDir = open(ExifDirFileName, O_RDONLY);
if (fd_ExifDir < 0) { // check control OK if (fd_ExifDir < 0) { // check control OK
D0(fprintf(debug_file, "Error opening %s\n", ExifDirFileName)); D0(fprintf(debug_file, "Error opening %s\n", ExifDirFileName));
...@@ -114,10 +81,10 @@ int camogm_start_kml(camogm_state *state) ...@@ -114,10 +81,10 @@ int camogm_start_kml(camogm_state *state)
if (indx >= 0) { if (indx >= 0) {
memcpy(&(state->kml_exif[indx]), &dir_table_entry, sizeof(dir_table_entry)); memcpy(&(state->kml_exif[indx]), &dir_table_entry, sizeof(dir_table_entry));
D2(fprintf(debug_file, "indx=%02d, ltag=0x%05x, len=0x%03x, src=0x%03x, dst=0x%03x\n", indx, \ D2(fprintf(debug_file, "indx=%02d, ltag=0x%05x, len=0x%03x, src=0x%03x, dst=0x%03x\n", indx, \
(int)dir_table_entry.ltag, \ (int)dir_table_entry.ltag, \
(int)dir_table_entry.len, \ (int)dir_table_entry.len, \
(int)dir_table_entry.src, \ (int)dir_table_entry.src, \
(int)dir_table_entry.dst)); (int)dir_table_entry.dst));
} }
} }
close(fd_ExifDir); close(fd_ExifDir);
...@@ -126,14 +93,19 @@ int camogm_start_kml(camogm_state *state) ...@@ -126,14 +93,19 @@ int camogm_start_kml(camogm_state *state)
D0(fprintf(debug_file, "Error opening %s for writing\n", state->kml_path)); D0(fprintf(debug_file, "Error opening %s for writing\n", state->kml_path));
return -CAMOGM_FRAME_FILE_ERR; return -CAMOGM_FRAME_FILE_ERR;
} }
/// write start of the KML file // write start of the KML file
fprintf(state->kml_file, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" \ fprintf(state->kml_file, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" \
"<kml xmlns=\"http://earth.google.com/kml/2.2\">\n"); "<kml xmlns=\"http://earth.google.com/kml/2.2\">\n");
fprintf(state->kml_file, "<Document>\n"); fprintf(state->kml_file, "<Document>\n");
state->kml_used = 1; state->kml_used = 1;
return 0; return 0;
} }
/**
* @brief Write KML file for current frame
* @param[in] state a pointer to a structure containing current state
* @return 0 if file was created successfully and negative error code otherwise
*/
int camogm_frame_kml(camogm_state *state) int camogm_frame_kml(camogm_state *state)
{ {
char JPEGFileName[300]; char JPEGFileName[300];
...@@ -152,7 +124,7 @@ int camogm_frame_kml(camogm_state *state) ...@@ -152,7 +124,7 @@ int camogm_frame_kml(camogm_state *state)
if (state->kml_file) { // probably not needed if (state->kml_file) { // probably not needed
i = state->this_frame_params[state->port_num].timestamp_sec - (state->kml_last_ts + state->kml_period); i = state->this_frame_params[state->port_num].timestamp_sec - (state->kml_last_ts + state->kml_period);
if ((i > 1) || ((i == 0) && ( state->this_frame_params[state->port_num].timestamp_usec > state->kml_last_uts ))) { if ((i > 1) || ((i == 0) && ( state->this_frame_params[state->port_num].timestamp_usec > state->kml_last_uts ))) {
// if (state->this_frame_params.timestamp_sec > (state->kml_last_ts + state->kml_period)) { // this way it is safe to put kml_period=1000, then kml_period=1 // if (state->this_frame_params.timestamp_sec > (state->kml_last_ts + state->kml_period)) { // this way it is safe to put kml_period=1000, then kml_period=1
state->kml_last_ts = state->this_frame_params[state->port_num].timestamp_sec; state->kml_last_ts = state->this_frame_params[state->port_num].timestamp_sec;
state->kml_last_uts = state->this_frame_params[state->port_num].timestamp_usec; state->kml_last_uts = state->this_frame_params[state->port_num].timestamp_usec;
if (state->format == CAMOGM_FORMAT_JPEG) { if (state->format == CAMOGM_FORMAT_JPEG) {
...@@ -180,12 +152,12 @@ int camogm_frame_kml(camogm_state *state) ...@@ -180,12 +152,12 @@ int camogm_frame_kml(camogm_state *state)
} }
} }
/// now we have JPEGFileName written. find realtive (to KML) location: // now we have JPEGFileName written. find realtive (to KML) location:
filename = strrchr(JPEGFileName, '/'); filename = strrchr(JPEGFileName, '/');
filename[0] = '\0'; filename[0] = '\0';
filename++; filename++;
///generating KML itself // generating KML itself
/// Using GPS time - in the same structure // using GPS time - in the same structure
if (state->kml_exif[Exif_GPSInfo_GPSDateStamp_Index].ltag == Exif_GPSInfo_GPSDateStamp) { // Exif_GPSInfo_GPSDateStamp is present in template if (state->kml_exif[Exif_GPSInfo_GPSDateStamp_Index].ltag == Exif_GPSInfo_GPSDateStamp) { // Exif_GPSInfo_GPSDateStamp is present in template
memcpy(datestr, &(state->ed[port][state->kml_exif[Exif_GPSInfo_GPSDateStamp_Index].dst]), 10); memcpy(datestr, &(state->ed[port][state->kml_exif[Exif_GPSInfo_GPSDateStamp_Index].dst]), 10);
datestr[4] = '-'; datestr[7] = '-'; datestr[10] = '\0'; datestr[4] = '-'; datestr[7] = '-'; datestr[10] = '\0';
...@@ -194,23 +166,23 @@ int camogm_frame_kml(camogm_state *state) ...@@ -194,23 +166,23 @@ int camogm_frame_kml(camogm_state *state)
ip = (int*)&(state->ed[state->kml_exif[Exif_GPSInfo_GPSTimeStamp_Index].dst]); ip = (int*)&(state->ed[state->kml_exif[Exif_GPSInfo_GPSTimeStamp_Index].dst]);
hours = __cpu_to_be32( ip[0]); hours = __cpu_to_be32( ip[0]);
minutes = __cpu_to_be32( ip[2]); minutes = __cpu_to_be32( ip[2]);
seconds = (1.0 * (__cpu_to_be32( ip[4]) + 1)) / __cpu_to_be32( ip[5]); /// GPS likes ".999", let's inc by one - anyway will round that out seconds = (1.0 * (__cpu_to_be32( ip[4]) + 1)) / __cpu_to_be32( ip[5]); // GPS likes ".999", let's inc by one - anyway will round that out
D2(fprintf(debug_file, "(when) 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", ip[0], ip[1], ip[2], ip[3], ip[4], ip[5])); D2(fprintf(debug_file, "(when) 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", ip[0], ip[1], ip[2], ip[3], ip[4], ip[5]));
D2(fprintf(debug_file, "(when) 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", __cpu_to_be32(ip[0]), \ D2(fprintf(debug_file, "(when) 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", __cpu_to_be32(ip[0]), \
__cpu_to_be32(ip[1]), \ __cpu_to_be32(ip[1]), \
__cpu_to_be32(ip[2]), \ __cpu_to_be32(ip[2]), \
__cpu_to_be32(ip[3]), \ __cpu_to_be32(ip[3]), \
__cpu_to_be32(ip[4]), \ __cpu_to_be32(ip[4]), \
__cpu_to_be32(ip[5]))); __cpu_to_be32(ip[5])));
} }
D1(fprintf(debug_file, "when=%sT%02d:%02d:%05.2fZ\n", datestr, hours, minutes, seconds)); D1(fprintf(debug_file, "when=%sT%02d:%02d:%05.2fZ\n", datestr, hours, minutes, seconds));
/// knowing format provided from GPS - degrees and minuts only, no seconds: // knowing format provided from GPS - degrees and minuts only, no seconds:
if (state->kml_exif[Exif_GPSInfo_GPSLongitude_Index].ltag == Exif_GPSInfo_GPSLongitude) { // Exif_GPSInfo_GPSLongitude is present in template if (state->kml_exif[Exif_GPSInfo_GPSLongitude_Index].ltag == Exif_GPSInfo_GPSLongitude) { // Exif_GPSInfo_GPSLongitude is present in template
ip = (int*)&(state->ed[state->kml_exif[Exif_GPSInfo_GPSLongitude_Index].dst]); ip = (int*)&(state->ed[state->kml_exif[Exif_GPSInfo_GPSLongitude_Index].dst]);
longitude = __cpu_to_be32( ip[0]) / (1.0 * __cpu_to_be32( ip[1])) + __cpu_to_be32( ip[2]) / (60.0 * __cpu_to_be32( ip[3])); longitude = __cpu_to_be32( ip[0]) / (1.0 * __cpu_to_be32( ip[1])) + __cpu_to_be32( ip[2]) / (60.0 * __cpu_to_be32( ip[3]));
if ((state->kml_exif[Exif_GPSInfo_GPSLongitudeRef_Index].ltag == Exif_GPSInfo_GPSLongitudeRef) && if ((state->kml_exif[Exif_GPSInfo_GPSLongitudeRef_Index].ltag == Exif_GPSInfo_GPSLongitudeRef) &&
(state->ed[port][state->kml_exif[Exif_GPSInfo_GPSLongitudeRef_Index].dst] != 'E')) longitude = -longitude; (state->ed[port][state->kml_exif[Exif_GPSInfo_GPSLongitudeRef_Index].dst] != 'E')) longitude = -longitude;
D2(fprintf(debug_file, "(longitude) 0x%x 0x%x 0x%x 0x%x '%c'\n", ip[0], ip[1], ip[2], ip[3], state->ed[port][state->kml_exif[Exif_GPSInfo_GPSLongitudeRef_Index].dst])); D2(fprintf(debug_file, "(longitude) 0x%x 0x%x 0x%x 0x%x '%c'\n", ip[0], ip[1], ip[2], ip[3], state->ed[port][state->kml_exif[Exif_GPSInfo_GPSLongitudeRef_Index].dst]));
} }
...@@ -218,32 +190,32 @@ int camogm_frame_kml(camogm_state *state) ...@@ -218,32 +190,32 @@ int camogm_frame_kml(camogm_state *state)
ip = (int*)&(state->ed[port][state->kml_exif[Exif_GPSInfo_GPSLatitude_Index].dst]); ip = (int*)&(state->ed[port][state->kml_exif[Exif_GPSInfo_GPSLatitude_Index].dst]);
latitude = __cpu_to_be32( ip[0]) / (1.0 * __cpu_to_be32( ip[1])) + __cpu_to_be32( ip[2]) / (60.0 * __cpu_to_be32( ip[3])); latitude = __cpu_to_be32( ip[0]) / (1.0 * __cpu_to_be32( ip[1])) + __cpu_to_be32( ip[2]) / (60.0 * __cpu_to_be32( ip[3]));
if ((state->kml_exif[Exif_GPSInfo_GPSLatitudeRef_Index].ltag == Exif_GPSInfo_GPSLatitudeRef) && if ((state->kml_exif[Exif_GPSInfo_GPSLatitudeRef_Index].ltag == Exif_GPSInfo_GPSLatitudeRef) &&
(state->ed[port][state->kml_exif[Exif_GPSInfo_GPSLatitudeRef_Index].dst] != 'N')) latitude = -latitude; (state->ed[port][state->kml_exif[Exif_GPSInfo_GPSLatitudeRef_Index].dst] != 'N')) latitude = -latitude;
D2(fprintf(debug_file, "(latitude) 0x%x 0x%x 0x%x 0x%x '%c'\n", ip[0], ip[1], ip[2], ip[3], state->ed[port][state->kml_exif[Exif_GPSInfo_GPSLatitudeRef_Index].dst] ? '-' : '+')); D2(fprintf(debug_file, "(latitude) 0x%x 0x%x 0x%x 0x%x '%c'\n", ip[0], ip[1], ip[2], ip[3], state->ed[port][state->kml_exif[Exif_GPSInfo_GPSLatitudeRef_Index].dst] ? '-' : '+'));
} }
/// altitude - will be modified/replaced later // altitude - will be modified/replaced later
if (state->kml_exif[Exif_GPSInfo_GPSAltitude_Index].ltag == Exif_GPSInfo_GPSAltitude) { // Exif_GPSInfo_GPSAltitude is present in template if (state->kml_exif[Exif_GPSInfo_GPSAltitude_Index].ltag == Exif_GPSInfo_GPSAltitude) { // Exif_GPSInfo_GPSAltitude is present in template
ip = (int*)&(state->ed[port][state->kml_exif[Exif_GPSInfo_GPSAltitude_Index].dst]); ip = (int*)&(state->ed[port][state->kml_exif[Exif_GPSInfo_GPSAltitude_Index].dst]);
altitude = (1.0 * __cpu_to_be32( ip[0])) / __cpu_to_be32( ip[1]); altitude = (1.0 * __cpu_to_be32( ip[0])) / __cpu_to_be32( ip[1]);
if ((state->kml_exif[Exif_GPSInfo_GPSAltitudeRef_Index].ltag == Exif_GPSInfo_GPSAltitudeRef) && if ((state->kml_exif[Exif_GPSInfo_GPSAltitudeRef_Index].ltag == Exif_GPSInfo_GPSAltitudeRef) &&
(state->ed[port][state->kml_exif[Exif_GPSInfo_GPSAltitudeRef_Index].dst] != '\0')) altitude = -altitude; (state->ed[port][state->kml_exif[Exif_GPSInfo_GPSAltitudeRef_Index].dst] != '\0')) altitude = -altitude;
D2(fprintf(debug_file, "(altitude) 0x%x 0x%x '%c'\n", ip[0], ip[1], state->ed[port][state->kml_exif[Exif_GPSInfo_GPSAltitudeRef_Index].dst])); D2(fprintf(debug_file, "(altitude) 0x%x 0x%x '%c'\n", ip[0], ip[1], state->ed[port][state->kml_exif[Exif_GPSInfo_GPSAltitudeRef_Index].dst]));
} }
D1(fprintf(debug_file, "longitude=%f, latitude=%f, altitude=%f\n", longitude, latitude, altitude)); D1(fprintf(debug_file, "longitude=%f, latitude=%f, altitude=%f\n", longitude, latitude, altitude));
/// Heading - no processing of "True/Magnetic" Exif_GPSInfo_CompassDirectionRef now (always M) // heading - no processing of "True/Magnetic" Exif_GPSInfo_CompassDirectionRef now (always M)
if (state->kml_exif[Exif_GPSInfo_CompassDirection_Index].ltag == Exif_GPSInfo_CompassDirection) { // Exif_GPSInfo_CompassDirection is present in template if (state->kml_exif[Exif_GPSInfo_CompassDirection_Index].ltag == Exif_GPSInfo_CompassDirection) { // Exif_GPSInfo_CompassDirection is present in template
ip = (int*)&(state->ed[port][state->kml_exif[Exif_GPSInfo_CompassDirection_Index].dst]); ip = (int*)&(state->ed[port][state->kml_exif[Exif_GPSInfo_CompassDirection_Index].dst]);
heading = (1.0 * __cpu_to_be32( ip[0])) / __cpu_to_be32( ip[1]); heading = (1.0 * __cpu_to_be32( ip[0])) / __cpu_to_be32( ip[1]);
D2(fprintf(debug_file, "(heading) 0x%x 0x%x\n", ip[0], ip[1])); D2(fprintf(debug_file, "(heading) 0x%x 0x%x\n", ip[0], ip[1]));
} }
///Processing 'hacked' pitch and roll (made of Exif destination latitude/longitude) // processing 'hacked' pitch and roll (made of Exif destination latitude/longitude)
if (state->kml_exif[Exif_GPSInfo_CompassRoll_Index].ltag == Exif_GPSInfo_CompassRoll) { // Exif_GPSInfo_CompassRoll is present in template if (state->kml_exif[Exif_GPSInfo_CompassRoll_Index].ltag == Exif_GPSInfo_CompassRoll) { // Exif_GPSInfo_CompassRoll is present in template
ip = (int*)&(state->ed[state->kml_exif[Exif_GPSInfo_CompassRoll_Index].dst]); ip = (int*)&(state->ed[state->kml_exif[Exif_GPSInfo_CompassRoll_Index].dst]);
roll = __cpu_to_be32( ip[0]) / (1.0 * __cpu_to_be32( ip[1])) + __cpu_to_be32( ip[2]) / (60.0 * __cpu_to_be32( ip[3])); roll = __cpu_to_be32( ip[0]) / (1.0 * __cpu_to_be32( ip[1])) + __cpu_to_be32( ip[2]) / (60.0 * __cpu_to_be32( ip[3]));
if ((state->kml_exif[Exif_GPSInfo_CompassRollRef_Index].ltag == Exif_GPSInfo_CompassRollRef) && if ((state->kml_exif[Exif_GPSInfo_CompassRollRef_Index].ltag == Exif_GPSInfo_CompassRollRef) &&
(state->ed[port][state->kml_exif[Exif_GPSInfo_CompassRollRef_Index].dst] != EXIF_COMPASS_ROLL_ASCII[0])) roll = -roll; (state->ed[port][state->kml_exif[Exif_GPSInfo_CompassRollRef_Index].dst] != EXIF_COMPASS_ROLL_ASCII[0])) roll = -roll;
D2(fprintf(debug_file, "(roll) 0x%x 0x%x '%c'\n", ip[0], ip[1], state->ed[port][state->kml_exif[Exif_GPSInfo_CompassRollRef_Index].dst])); D2(fprintf(debug_file, "(roll) 0x%x 0x%x '%c'\n", ip[0], ip[1], state->ed[port][state->kml_exif[Exif_GPSInfo_CompassRollRef_Index].dst]));
} }
...@@ -251,54 +223,61 @@ int camogm_frame_kml(camogm_state *state) ...@@ -251,54 +223,61 @@ int camogm_frame_kml(camogm_state *state)
ip = (int*)&(state->ed[port][state->kml_exif[Exif_GPSInfo_CompassPitch_Index].dst]); ip = (int*)&(state->ed[port][state->kml_exif[Exif_GPSInfo_CompassPitch_Index].dst]);
pitch = __cpu_to_be32( ip[0]) / (1.0 * __cpu_to_be32( ip[1])) + __cpu_to_be32( ip[2]) / (60.0 * __cpu_to_be32( ip[3])); pitch = __cpu_to_be32( ip[0]) / (1.0 * __cpu_to_be32( ip[1])) + __cpu_to_be32( ip[2]) / (60.0 * __cpu_to_be32( ip[3]));
if ((state->kml_exif[Exif_GPSInfo_CompassPitchRef_Index].ltag == Exif_GPSInfo_CompassPitchRef) && if ((state->kml_exif[Exif_GPSInfo_CompassPitchRef_Index].ltag == Exif_GPSInfo_CompassPitchRef) &&
(state->ed[port][state->kml_exif[Exif_GPSInfo_CompassPitchRef_Index].dst] != EXIF_COMPASS_PITCH_ASCII[0])) pitch = -pitch; (state->ed[port][state->kml_exif[Exif_GPSInfo_CompassPitchRef_Index].dst] != EXIF_COMPASS_PITCH_ASCII[0])) pitch = -pitch;
D2(fprintf(debug_file, "(pitch) 0x%x 0x%x '%c'\n", ip[0], ip[1], state->ed[port][state->kml_exif[Exif_GPSInfo_CompassPitchRef_Index].dst])); D2(fprintf(debug_file, "(pitch) 0x%x 0x%x '%c'\n", ip[0], ip[1], state->ed[port][state->kml_exif[Exif_GPSInfo_CompassPitchRef_Index].dst]));
} }
/// convert from GPS heading, pitch, roll to KML heading, tilt, roll // convert from GPS heading, pitch, roll to KML heading, tilt, roll
tilt = pitch + 90.0; tilt = pitch + 90.0;
if (tilt < 0.0) tilt = 0; if (tilt < 0.0) tilt = 0;
else if (tilt > 180.0) tilt = 180.0; else if (tilt > 180.0) tilt = 180.0;
D2(fprintf(debug_file, "heading=%f, roll=%f, pitch=%f, tilt=%f\n", heading, roll, pitch, tilt)); D2(fprintf(debug_file, "heading=%f, roll=%f, pitch=%f, tilt=%f\n", heading, roll, pitch, tilt));
/// modify altitude // modify altitude
altitude = (state->kml_height_mode ? altitude : 0.0) + state->kml_height; altitude = (state->kml_height_mode ? altitude : 0.0) + state->kml_height;
/// write to KML // write to KML
fprintf(state->kml_file, "<PhotoOverlay>\n" \ fprintf(state->kml_file, "<PhotoOverlay>\n" \
" <shape>rectangle</shape>\n" \ " <shape>rectangle</shape>\n" \
" <TimeStamp>\n" \ " <TimeStamp>\n" \
" <when>%sT%02d:%02d:%05.2fZ</when>\n" \ " <when>%sT%02d:%02d:%05.2fZ</when>\n" \
" </TimeStamp>\n" \ " </TimeStamp>\n" \
" <Icon>\n" \ " <Icon>\n" \
" <href>%s</href>\n" \ " <href>%s</href>\n" \
" </Icon>\n" \ " </Icon>\n" \
" <Camera>\n" \ " <Camera>\n" \
" <longitude>%f</longitude>\n" \ " <longitude>%f</longitude>\n" \
" <latitude>%f</latitude>\n" \ " <latitude>%f</latitude>\n" \
" <altitude>%f</altitude>\n" \ " <altitude>%f</altitude>\n" \
" <heading>%f</heading>\n" \ " <heading>%f</heading>\n" \
" <tilt>%f</tilt>\n" \ " <tilt>%f</tilt>\n" \
" <roll>%f</roll>\n" \ " <roll>%f</roll>\n" \
" <altitudeMode>%s</altitudeMode>\n" \ " <altitudeMode>%s</altitudeMode>\n" \
" </Camera>\n" \ " </Camera>\n" \
" <ViewVolume>\n" \ " <ViewVolume>\n" \
" <leftFov>%f</leftFov>\n" \ " <leftFov>%f</leftFov>\n" \
" <rightFov>%f</rightFov>\n" \ " <rightFov>%f</rightFov>\n" \
" <bottomFov>%f</bottomFov>\n" \ " <bottomFov>%f</bottomFov>\n" \
" <topFov>%f</topFov>\n" \ " <topFov>%f</topFov>\n" \
" <near>%f</near>\n" \ " <near>%f</near>\n" \
" </ViewVolume>\n" \ " </ViewVolume>\n" \
"</PhotoOverlay>\n", \ "</PhotoOverlay>\n", \
datestr, hours, minutes, seconds, \ datestr, hours, minutes, seconds, \
filename, longitude, latitude, altitude, heading, tilt, roll, state->kml_height_mode ? "absolute" : "relativeToGround", \ filename, longitude, latitude, altitude, heading, tilt, roll, state->kml_height_mode ? "absolute" : "relativeToGround", \
-(state->kml_horHalfFov), state->kml_horHalfFov, -(state->kml_vertHalfFov), state->kml_vertHalfFov, state->kml_near); -(state->kml_horHalfFov), state->kml_horHalfFov, -(state->kml_vertHalfFov), state->kml_vertHalfFov, state->kml_near);
} }
} }
return 0; return 0;
} }
/**
* @brief Finish KML file write operation
*
* This function writes trailing XML tags and closes KML file
* @param[in] state a pointer to a structure containing current state
* @return always 0
*/
int camogm_end_kml(camogm_state *state) int camogm_end_kml(camogm_state *state)
{ {
......
/** @file camogm_kml.h
* @brief Provides writing to series of individual KML files for @e camogm
* @copyright Copyright (C) 2016 Elphel, Inc.
*
* @par <b>License</b>
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _CAMOGM_KML_H #ifndef _CAMOGM_KML_H
#define _CAMOGM_KML_H #define _CAMOGM_KML_H
......
/*!*************************************************************************** /** @file camogm_mov.c
*! FILE NAME : camogm_mov.c * @brief Provides writing to file compatible with Apple Quicktime(R) for @e camogm
*! DESCRIPTION: Provides writing to file compatible with Apple Quicktime(R) for camogm * @copyright Copyright (C) 2016 Elphel, Inc.
*!TODO: Nothing yet here, will be added ASAP *
*! Copyright (C) 2007 Elphel, Inc. * @par <b>License</b>
*! -----------------------------------------------------------------------------** * This program is free software: you can redistribute it and/or modify
*! This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by
*! it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or
*! the Free Software Foundation, either version 3 of the License, or * (at your option) any later version.
*! (at your option) any later version. * This program is distributed in the hope that it will be useful,
*! * but WITHOUT ANY WARRANTY; without even the implied warranty of
*! This program is distributed in the hope that it will be useful, * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
*! but WITHOUT ANY WARRANTY; without even the implied warranty of * GNU General Public License for more details.
*! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * You should have received a copy of the GNU General Public License
*! GNU General Public License for more details. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*!
*! You should have received a copy of the GNU General Public License
*! along with this program. If not, see <http://www.gnu.org/licenses/>.
*! -----------------------------------------------------------------------------**
*!
*! $Log: camogm_mov.c,v $
*! Revision 1.2 2009/02/25 17:50:02 spectr_rain
*! removed deprecated dependency
*!
*! Revision 1.1.1.1 2008/11/27 20:04:01 elphel
*!
*!
*! Revision 1.4 2008/04/11 23:09:33 elphel
*! modified to handle kml generation
*!
*! Revision 1.3 2007/11/19 17:00:20 elphel
*! removed wrong dependency
*!
*! Revision 1.2 2007/11/19 03:23:21 elphel
*! 7.1.5.5 Added support for *.mov files in camogm.
*!
*! Revision 1.1 2007/11/16 08:49:57 elphel
*! Initial release of camogm - program to record video/image to the camera hard drive (or other storage)
*!
*/ */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <fcntl.h> #include <fcntl.h>
...@@ -50,11 +27,10 @@ ...@@ -50,11 +27,10 @@
#include "camogm_mov.h" #include "camogm_mov.h"
#define QUICKTIME_MIN_HEADER 0x300 // Quicktime header length (w/o index tables) enough to accomodate /** @brief Quicktime header length (w/o index tables) enough to accommodate static data */
// static data . #define QUICKTIME_MIN_HEADER 0x300
//! for the parser // for the parser
const char hexStr[] = "0123456789abcdef"; const char hexStr[] = "0123456789abcdef";
const char qtSourceFileName[] = "/etc/qt_source"; const char qtSourceFileName[] = "/etc/qt_source";
char comStr[1024]; char comStr[1024];
...@@ -66,8 +42,7 @@ int samplesPerChunk = 10; ...@@ -66,8 +42,7 @@ int samplesPerChunk = 10;
int framesize = 80000; int framesize = 80000;
int timescale = 600; int timescale = 600;
int * sizes; // array of frame sizes int * sizes; // array of frame sizes
int iPos; //!position in the string "iFile" int iPos; // position in the string "iFile"
//int oPos; //!position in the string "oFile"
int ofd; // output file descriptor (file opened by the caller) int ofd; // output file descriptor (file opened by the caller)
int iFileLen; int iFileLen;
char * q_template = NULL; char * q_template = NULL;
...@@ -76,23 +51,26 @@ const char *iFile = NULL; ...@@ -76,23 +51,26 @@ const char *iFile = NULL;
int quicktime_template_parser(camogm_state *state, int quicktime_template_parser(camogm_state *state,
const char * i_iFile, //! now - string containing header template const char * i_iFile, // now - string containing header template
int i_ofd, //!output file descriptor (opened) int i_ofd, // output file descriptor (opened)
int i_width, // width in pixels int i_width, // width in pixels
int i_height, int i_height,
int i_nframes, int i_nframes,
int i_sample_dur, int i_sample_dur,
int i_samplesPerChunk, int i_samplesPerChunk,
int i_framesize, int i_framesize,
int i_timescale, int i_timescale,
int * i_sizes, int * i_sizes,
int data_start // put zero if the header is written before data (no gap) int data_start // put zero if the header is written before data (no gap)
); );
void putBigEndian(unsigned long d, int l); void putBigEndian(unsigned long d, int l);
int parse_special(void); int parse_special(void);
int parse(camogm_state *state, int top); int parse(camogm_state *state, int top);
//! called first time format is changed to this one (only once) recording is stopped
//! read frame template from the file if it is not done yet /**
* @brief Called when format is changed to MOV (only once) and recording is stopped.
* Read frame template from the file if it is not done yet.
*/
int camogm_init_mov(void) int camogm_init_mov(void)
{ {
FILE* qt_header; FILE* qt_header;
...@@ -104,7 +82,6 @@ int camogm_init_mov(void) ...@@ -104,7 +82,6 @@ int camogm_init_mov(void)
} }
fseek(qt_header, 0, SEEK_END); fseek(qt_header, 0, SEEK_END);
size = ftell(qt_header); size = ftell(qt_header);
//malloc(4*state->max_frames);
if (!((q_template = malloc(size + 1)))) { if (!((q_template = malloc(size + 1)))) {
D0(fprintf(debug_file, "Could not allocate %d bytes of memory for Quicktime header template\n", (size + 1))); D0(fprintf(debug_file, "Could not allocate %d bytes of memory for Quicktime header template\n", (size + 1)));
fclose(qt_header); fclose(qt_header);
...@@ -130,24 +107,34 @@ void camogm_free_mov(void) ...@@ -130,24 +107,34 @@ void camogm_free_mov(void)
} }
} }
/**
* @brief Start MOV recording
* @param[in] state a pointer to a structure containing current state
* @return 0 if recording started successfully and negative error code otherwise
*/
int camogm_start_mov(camogm_state *state) int camogm_start_mov(camogm_state *state)
{ {
//! allocate memory for the frame index table // allocate memory for the frame index table
if (!((state->frame_lengths = malloc(4 * state->max_frames)))) return -CAMOGM_FRAME_MALLOC; if (!((state->frame_lengths = malloc(4 * state->max_frames)))) return -CAMOGM_FRAME_MALLOC;
//! open file for writing // open file for writing
sprintf(state->path, "%s%010ld_%06ld.mov", state->path_prefix, state->frame_params[state->port_num].timestamp_sec, state->frame_params[state->port_num].timestamp_usec); sprintf(state->path, "%s%010ld_%06ld.mov", state->path_prefix, state->frame_params[state->port_num].timestamp_sec, state->frame_params[state->port_num].timestamp_usec);
if (((state->ivf = open(state->path, O_RDWR | O_CREAT, 0777))) < 0) { if (((state->ivf = open(state->path, O_RDWR | O_CREAT, 0777))) < 0) {
D0(fprintf(debug_file, "Error opening %s for writing, returned %d, errno=%d\n", state->path, state->ivf, errno)); D0(fprintf(debug_file, "Error opening %s for writing, returned %d, errno=%d\n", state->path, state->ivf, errno));
return -CAMOGM_FRAME_FILE_ERR; return -CAMOGM_FRAME_FILE_ERR;
} }
//!skip header (plus extra) // skip header (plus extra)
//! Quicktime (and else?) - frame data start (0xff 0xd8...) // Quicktime (and else?) - frame data start (0xff 0xd8...)
state->frame_data_start = QUICKTIME_MIN_HEADER + 16 + 4 * (state->max_frames) + ( 4 * (state->max_frames)) / (state->frames_per_chunk); // 8 bytes for "skip" tag state->frame_data_start = QUICKTIME_MIN_HEADER + 16 + 4 * (state->max_frames) + ( 4 * (state->max_frames)) / (state->frames_per_chunk); // 8 bytes for "skip" tag
lseek(state->ivf, state->frame_data_start, SEEK_SET); lseek(state->ivf, state->frame_data_start, SEEK_SET);
return 0; return 0;
} }
/**
* @brief Write a frame to file
* @param[in] state a pointer to a structure containing current state
* @return 0 if frame was saved successfully and negative error code otherwise
*/
int camogm_frame_mov(camogm_state *state) int camogm_frame_mov(camogm_state *state)
{ {
int i, j; int i, j;
...@@ -180,34 +167,31 @@ int camogm_frame_mov(camogm_state *state) ...@@ -180,34 +167,31 @@ int camogm_frame_mov(camogm_state *state)
*/ */
int camogm_end_mov(camogm_state *state) int camogm_end_mov(camogm_state *state)
{ {
off_t l/*,he; off_t l;
unsigned char mdat_tag[8];
unsigned char skip_tag[]="\0\0\0\0skip"*/;
int port = state->port_num; int port = state->port_num;
timescale = 10000; //! frame period measured in 1/10000 of a second? timescale = 10000; // frame period measured in 1/10000 of a second?
//! that was in old code. If that works - try to switch to microseconds // that was in old code. If that works - try to switch to microseconds
l = lseek(state->ivf, 0, SEEK_CUR) - (state->frame_data_start) + 8; //!4-byte length+"mdat" l = lseek(state->ivf, 0, SEEK_CUR) - (state->frame_data_start) + 8; // 4-byte length+"mdat"
// lseek(state->ivf, state->frame_data_start, SEEK_SET); // fill in the header in the beginning of the file
// fill in the header in the beginning of the file
lseek(state->ivf, 0, SEEK_SET); lseek(state->ivf, 0, SEEK_SET);
quicktime_template_parser(state, quicktime_template_parser(state,
q_template, //! now - string containing header template q_template, // now - string containing header template
state->ivf, //!output file descriptor (opened) state->ivf, // output file descriptor (opened)
state->width, //! width in pixels state->width, // width in pixels
state->height, state->height,
state->frameno, state->frameno,
state->frame_period[port] / (1000000 / timescale), state->frame_period[port] / (1000000 / timescale),
state->frames_per_chunk, state->frames_per_chunk,
0, //!frame size - will look in the table 0, // frame size - will look in the table
(int)((float)timescale / (state->timescale)), (int)((float)timescale / (state->timescale)),
state->frame_lengths, //! array of frame lengths to build an index state->frame_lengths, // array of frame lengths to build an index
state->frame_data_start state->frame_data_start
); );
#if 0 #if 0
//! now we need to overwrite last mdat tag in the header to the skip the gap, instead of the length 'mdat // now we need to overwrite last mdat tag in the header to the skip the gap, instead of the length 'mdat
//! put length 'skip length 'mdat // put length 'skip length 'mdat
he = lseek(state->ivf, 0, SEEK_CUR); // just after the original header end he = lseek(state->ivf, 0, SEEK_CUR); // just after the original header end
l = state->frame_data_start - he; //! should be >= l = state->frame_data_start - he; // should be >=
D4(fprintf(debug_file, "Remaining gap between Quicktime header and the data is %d (it should be>=8) \n", (int)l)); D4(fprintf(debug_file, "Remaining gap between Quicktime header and the data is %d (it should be>=8) \n", (int)l));
lseek(state->ivf, he - 8, SEEK_SET); lseek(state->ivf, he - 8, SEEK_SET);
read(state->ivf, mdat_tag, 8); //!read calculated length+'mdat' tag read(state->ivf, mdat_tag, 8); //!read calculated length+'mdat' tag
...@@ -222,7 +206,7 @@ int camogm_end_mov(camogm_state *state) ...@@ -222,7 +206,7 @@ int camogm_end_mov(camogm_state *state)
#endif #endif
close(state->ivf); close(state->ivf);
state->ivf = -1; state->ivf = -1;
//! free memory used for index // free memory used for index
if (state->frame_lengths) { if (state->frame_lengths) {
free(state->frame_lengths); free(state->frame_lengths);
state->frame_lengths = NULL; state->frame_lengths = NULL;
...@@ -236,7 +220,7 @@ int camogm_end_mov(camogm_state *state) ...@@ -236,7 +220,7 @@ int camogm_end_mov(camogm_state *state)
* on exit - input pointer - after closing "}", output after it's output * on exit - input pointer - after closing "}", output after it's output
* @param[in] d * @param[in] d
* @param[in] l * @param[in] l
* @return none * @return None
*/ */
void putBigEndian(unsigned long d, int l) void putBigEndian(unsigned long d, int l)
{ {
...@@ -247,18 +231,16 @@ void putBigEndian(unsigned long d, int l) ...@@ -247,18 +231,16 @@ void putBigEndian(unsigned long d, int l)
od[1] = d >> 16; od[1] = d >> 16;
od[0] = d >> 24; od[0] = d >> 24;
if (l) write(ofd, &od[4 - l], l); if (l) write(ofd, &od[4 - l], l);
// oPos+=l;
} }
//!temporary replacement for fgets to read from string /** @brief Temporary replacement for fgets to read from string */
char * sfgets(char * str, int size, const char * stream, int * pos) char * sfgets(char * str, int size, const char * stream, int * pos)
{ {
int l; int l;
const char * eol = strchr(&stream[*pos], '\n'); const char * eol = strchr(&stream[*pos], '\n');
if (!eol) eol = stream + (strlen(stream) - 1); //!pointer to last before \0 if (!eol) eol = stream + (strlen(stream) - 1); // pointer to last before '\0'
l = (eol - stream) - (*pos); l = (eol - stream) - (*pos);
// if (l >= size) eol=stream+ (*pos+size-1);
if (l >= size) l = size - 1; if (l >= size) l = size - 1;
memcpy(str, &stream[*pos], l); memcpy(str, &stream[*pos], l);
str[l] = '\0'; str[l] = '\0';
...@@ -268,7 +250,6 @@ char * sfgets(char * str, int size, const char * stream, int * pos) ...@@ -268,7 +250,6 @@ char * sfgets(char * str, int size, const char * stream, int * pos)
int parse_special(void) int parse_special(void)
{ {
time_t ltime; time_t ltime;
int n, j, l; int n, j, l;
char str[256]; char str[256];
...@@ -276,7 +257,6 @@ int parse_special(void) ...@@ -276,7 +257,6 @@ int parse_special(void)
int i = 0; int i = 0;
int gap; int gap;
// while (((c=fgetc(infile))!=0x20) && (c!=0x09) && (c!=0x0a) && (c!=0x0d) && (c!=0x0) && (i<255) && ( feof(infile) == 0 )) str[i++]=c;
while (((c = iFile[iPos++]) != 0x20) && (c != 0x09) && (c != 0x0a) && (c != 0x0d) && (c != 0x0) && (i < 255) && ( iPos < iFileLen )) str[i++] = c; while (((c = iFile[iPos++]) != 0x20) && (c != 0x09) && (c != 0x0a) && (c != 0x0d) && (c != 0x0) && (i < 255) && ( iPos < iFileLen )) str[i++] = c;
str[i] = 0; str[i] = 0;
...@@ -328,7 +308,7 @@ int parse_special(void) ...@@ -328,7 +308,7 @@ int parse_special(void)
} else for (i = 0; i < n; i++) putBigEndian(headerSize + framesize * samplesPerChunk * i, 4); } else for (i = 0; i < n; i++) putBigEndian(headerSize + framesize * samplesPerChunk * i, 4);
return 0; return 0;
} }
//! a hack - invlude length'skip if data position (header size is known and there is a gap) // a hack - invlude length'skip if data position (header size is known and there is a gap)
if (strcmp(str, "data_size") == 0) { if (strcmp(str, "data_size") == 0) {
gap = headerSize - lseek(ofd, 0, SEEK_CUR) - 8; gap = headerSize - lseek(ofd, 0, SEEK_CUR) - 8;
if (gap > 0) { //!it should be exactly 0 if there is no gap or >8 if there is if (gap > 0) { //!it should be exactly 0 if there is no gap or >8 if there is
...@@ -367,30 +347,23 @@ int parse(camogm_state *state, int top) // if top - will not include length ...@@ -367,30 +347,23 @@ int parse(camogm_state *state, int top) // if top - will not include length
char * cp; char * cp;
D4(fprintf(debug_file, "parse(%x)\n", top)); D4(fprintf(debug_file, "parse(%x)\n", top));
// c=fgetc(infile);
c = iFile[iPos++]; c = iFile[iPos++];
D5(fprintf(debug_file, "%c", c)); D5(fprintf(debug_file, "%c", c));
// out_start=ftell (outfile);
// out_start=oPos;
// out_start=oPos=lseek(ofd,0,SEEK_CUR);
out_start = lseek(ofd, 0, SEEK_CUR); out_start = lseek(ofd, 0, SEEK_CUR);
if (!top) putBigEndian(0, 4); if (!top) putBigEndian(0, 4);
// while (( feof(infile) == 0 ) && (c!='}')) {
while (( iPos < iFileLen ) && (c != '}')) { while (( iPos < iFileLen ) && (c != '}')) {
// skip white spaces strchr // skip white spaces strchr
if ((c != ' ') && (c != 0x9) && (c != 0xa) && (c != 0xd)) { if ((c != ' ') && (c != 0x9) && (c != 0xa) && (c != 0xd)) {
if (c == '!') { if (c == '!') {
if (parse_special() < 0) return -1; if (parse_special() < 0) return -1;
} }
// children atoms // children atoms
else if (c == '{') { else if (c == '{') {
if (parse(state, 0) < 0) return -1; if (parse(state, 0) < 0) return -1;
// skip comments // skip comments
// } else if (c=='#') fgets( comStr, sizeof(comStr), infile);
} else if (c == '#') sfgets( comStr, sizeof(comStr), iFile, &iPos); } else if (c == '#') sfgets( comStr, sizeof(comStr), iFile, &iPos);
else if (c == '\'') { else if (c == '\'') {
// fgets ( comStr, sizeof(comStr), infile);
sfgets( comStr, sizeof(comStr), iFile, &iPos); sfgets( comStr, sizeof(comStr), iFile, &iPos);
if ((cp = strchr(comStr, 0x0a)) != NULL) cp[0] = 0; if ((cp = strchr(comStr, 0x0a)) != NULL) cp[0] = 0;
if ((cp = strchr(comStr, 0x0d)) != NULL) cp[0] = 0; if ((cp = strchr(comStr, 0x0d)) != NULL) cp[0] = 0;
...@@ -398,8 +371,6 @@ int parse(camogm_state *state, int top) // if top - will not include length ...@@ -398,8 +371,6 @@ int parse(camogm_state *state, int top) // if top - will not include length
cp = comStr + strlen(comStr) - 1; cp = comStr + strlen(comStr) - 1;
while ((cp > comStr) && ((cp[0] == 0x20) || (cp[0] == 0x09))) cp--; while ((cp > comStr) && ((cp[0] == 0x20) || (cp[0] == 0x09))) cp--;
cp[1] = 0; cp[1] = 0;
// fwrite (comStr,1, strlen(comStr),outfile);
// memcpy(&oFile[oPos],comStr,strlen(comStr));
write(ofd, comStr, strlen(comStr)); write(ofd, comStr, strlen(comStr));
D4(fprintf(debug_file, "writing string <%s>\n", comStr)); D4(fprintf(debug_file, "writing string <%s>\n", comStr));
} else if (strchr(hexStr, c)) { } else if (strchr(hexStr, c)) {
...@@ -423,22 +394,15 @@ int parse(camogm_state *state, int top) // if top - will not include length ...@@ -423,22 +394,15 @@ int parse(camogm_state *state, int top) // if top - will not include length
} }
} }
// c=fgetc(infile);
c = iFile[iPos++]; c = iFile[iPos++];
} }
// fread fseek ftell // fread fseek ftell
if (!top) { if (!top) {
// out_end=ftell (outfile);
// out_end=oPos;
out_end = lseek(ofd, 0, SEEK_CUR); out_end = lseek(ofd, 0, SEEK_CUR);
// fseek (outfile,out_start,SEEK_SET);
// oPos=out_start;
lseek(ofd, out_start, SEEK_SET); lseek(ofd, out_start, SEEK_SET);
putBigEndian((out_end - out_start), 4); putBigEndian((out_end - out_start), 4);
// fseek (outfile,out_end,SEEK_SET);
// oPos=out_end;
lseek(state->ivf, out_end, SEEK_SET); lseek(state->ivf, out_end, SEEK_SET);
} }
return 0; return 0;
...@@ -446,18 +410,18 @@ int parse(camogm_state *state, int top) // if top - will not include length ...@@ -446,18 +410,18 @@ int parse(camogm_state *state, int top) // if top - will not include length
int quicktime_template_parser( camogm_state *state, int quicktime_template_parser( camogm_state *state,
const char * i_iFile, //! now - string containing header template const char * i_iFile, // now - string containing header template
int i_ofd, //!output file descriptor (opened) int i_ofd, // output file descriptor (opened)
int i_width, // width in pixels int i_width, // width in pixels
int i_height, int i_height,
int i_nframes, int i_nframes,
int i_sample_dur, int i_sample_dur,
int i_samplesPerChunk, int i_samplesPerChunk,
int i_framesize, int i_framesize,
int i_timescale, int i_timescale,
int * i_sizes, int * i_sizes,
int data_start // zero if dfata is not written yet (will be no gap) int data_start // zero if dfata is not written yet (will be no gap)
) )
{ {
iFile = i_iFile; iFile = i_iFile;
width = i_width; width = i_width;
...@@ -468,31 +432,20 @@ int quicktime_template_parser( camogm_state *state, ...@@ -468,31 +432,20 @@ int quicktime_template_parser( camogm_state *state,
framesize = i_framesize; framesize = i_framesize;
timescale = i_timescale; timescale = i_timescale;
sizes = i_sizes; sizes = i_sizes;
iPos = 0; //!position in the string "iFile" iPos = 0; // position in the string "iFile"
ofd = i_ofd; ofd = i_ofd;
iFileLen = strlen(iFile); iFileLen = strlen(iFile);
lseek(ofd, 0, SEEK_SET); lseek(ofd, 0, SEEK_SET);
if (data_start) headerSize = data_start; if (data_start) headerSize = data_start;
// int iFileLen=strlen(inFIle);
D3(fprintf(debug_file, "PASS I\n")); D3(fprintf(debug_file, "PASS I\n"));
// while ( feof(infile) == 0 ) parse(1); // pass 1
while ( iPos < iFileLen ) parse(state, 1); // pass 1 while ( iPos < iFileLen ) parse(state, 1); // pass 1
// headerSize=ftell (outfile);
// fseek (outfile,0,SEEK_SET); // rewind for pass 2
// fseek (infile, 0,SEEK_SET); //
// headerSize=oPos;
if (!headerSize) headerSize = lseek(ofd, 0, SEEK_CUR); if (!headerSize) headerSize = lseek(ofd, 0, SEEK_CUR);
iPos = 0; iPos = 0;
// oPos=0;
lseek(ofd, 0, SEEK_SET); lseek(ofd, 0, SEEK_SET);
D3(fprintf(debug_file, "PASS II\n")); D3(fprintf(debug_file, "PASS II\n"));
// while ( feof(infile) == 0 ) parse(1); // pass 2
while ( iPos < iFileLen ) parse(state, 1); // pass 2 while ( iPos < iFileLen ) parse(state, 1); // pass 2
//fclose (infile);
//fclose (outfile);
// oFile[oPos]='\0';
return 0; return 0;
} }
/** @file camogm_mov.h
* @brief Provides writing to file compatible with Apple Quicktime(R) for @e camogm
* @copyright Copyright (C) 2016 Elphel, Inc.
*
* @par <b>License</b>
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _CAMOGM_MOV_H #ifndef _CAMOGM_MOV_H
#define _CAMOG_MOV_H #define _CAMOG_MOV_H
......
/*!*************************************************************************** /** @file camogm_ogm.c
*! FILE NAME : camogm_ogm.c * @brief Provides writing to OGM files for @e camogm
*! DESCRIPTION: Provides writing to ogm files for camogm * @copyright Copyright (C) 2016 Elphel, Inc.
*! Copyright (C) 2007 Elphel, Inc. *
*! -----------------------------------------------------------------------------** * @par <b>License</b>
*! This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
*! it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
*! the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
*! (at your option) any later version. * (at your option) any later version.
*! * This program is distributed in the hope that it will be useful,
*! This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of
*! but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
*! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details.
*! GNU General Public License for more details. * You should have received a copy of the GNU General Public License
*! * along with this program. If not, see <http://www.gnu.org/licenses/>.
*! You should have received a copy of the GNU General Public License
*! along with this program. If not, see <http://www.gnu.org/licenses/>.
*! -----------------------------------------------------------------------------**
*!
*! $Log: camogm_ogm.c,v $
*! Revision 1.2 2009/02/25 17:50:02 spectr_rain
*! removed deprecated dependency
*!
*! Revision 1.1.1.1 2008/11/27 20:04:01 elphel
*!
*!
*! Revision 1.2 2007/11/19 03:23:21 elphel
*! 7.1.5.5 Added support for *.mov files in camogm.
*!
*! Revision 1.1 2007/11/16 08:49:58 elphel
*! Initial release of camogm - program to record video/image to the camera hard drive (or other storage)
*!
*/ */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <fcntl.h> #include <fcntl.h>
...@@ -40,15 +24,23 @@ ...@@ -40,15 +24,23 @@
#include "camogm_ogm.h" #include "camogm_ogm.h"
//! may add something - called first time format is changed to this one (only once) recording is stopped /**
* @brief Called when format is changed to OGM (only once) and recording is stopped
*/
int camogm_init_ogm(void) int camogm_init_ogm(void)
{ {
return 0; return 0;
} }
void camogm_free_ogm(void) void camogm_free_ogm(void)
{ {
} }
/**
* @brief Start OGM recording
* @param[in] state a pointer to a structure containing current state
* @return 0 if recording started successfully and negative error code otherwise
*/
int camogm_start_ogm(camogm_state *state) int camogm_start_ogm(camogm_state *state)
{ {
char vendor[] = "ElphelOgm v 0.1"; char vendor[] = "ElphelOgm v 0.1";
...@@ -68,19 +60,16 @@ int camogm_start_ogm(camogm_state *state) ...@@ -68,19 +60,16 @@ int camogm_start_ogm(camogm_state *state)
memcpy(sh.streamtype, "video", 5); memcpy(sh.streamtype, "video", 5);
memcpy(sh.subtype, "MJPG", 4); memcpy(sh.subtype, "MJPG", 4);
put_uint32(&sh.size, sizeof(sh)); put_uint32(&sh.size, sizeof(sh));
// put_uint64(&sh.time_unit, (ogg_int64_t) 10*state->frame_period);
put_uint64(&sh.time_unit, state->time_unit); put_uint64(&sh.time_unit, state->time_unit);
// put_uint64(&sh.samples_per_unit, 1);
put_uint64(&sh.samples_per_unit, (ogg_int64_t)state->timescale); put_uint64(&sh.samples_per_unit, (ogg_int64_t)state->timescale);
put_uint32(&sh.default_len, 1); put_uint32(&sh.default_len, 1);
put_uint32(&sh.buffersize, state->width * state->height); put_uint32(&sh.buffersize, state->width * state->height);
// put_uint16(&sh.bits_per_sample, 24); //? put_uint16(&sh.bits_per_sample, 0);
put_uint16(&sh.bits_per_sample, 0); //?
put_uint32(&sh.sh.video.width, state->width); put_uint32(&sh.sh.video.width, state->width);
put_uint32(&sh.sh.video.height, state->height); put_uint32(&sh.sh.video.height, state->height);
memcpy(&hdbuf[1], &sh, sizeof(sh)); memcpy(&hdbuf[1], &sh, sizeof(sh));
hdbuf[0] = 1; hdbuf[0] = 1;
//! put it into Ogg stream // put it into Ogg stream
ogg_header.packet = hdbuf; ogg_header.packet = hdbuf;
ogg_header.bytes = sizeof(sh) + 1; ogg_header.bytes = sizeof(sh) + 1;
ogg_header.b_o_s = 1; ogg_header.b_o_s = 1;
...@@ -89,19 +78,19 @@ int camogm_start_ogm(camogm_state *state) ...@@ -89,19 +78,19 @@ int camogm_start_ogm(camogm_state *state)
ogg_header.granulepos = 0; ogg_header.granulepos = 0;
ogg_stream_packetin(&(state->os), &ogg_header); ogg_stream_packetin(&(state->os), &ogg_header);
// while(ogg_stream_pageout(&(state->os), &(state->og))) { // while(ogg_stream_pageout(&(state->os), &(state->og))) {
while (ogg_stream_flush(&(state->os), &(state->og))) { while (ogg_stream_flush(&(state->os), &(state->og))) {
int i, j; int i, j;
if ((((i = fwrite(state->og.header, 1, state->og.header_len, state->vf))) != state->og.header_len) || if ((((i = fwrite(state->og.header, 1, state->og.header_len, state->vf))) != state->og.header_len) ||
(state->og.body_len && (((i = fwrite(state->og.body, 1, state->og.body_len, state->vf))) != state->og.body_len))) { (state->og.body_len && (((i = fwrite(state->og.body, 1, state->og.body_len, state->vf))) != state->og.body_len))) {
j = errno; j = errno;
D2(fprintf(debug_file, "\n%d %ld %ld\n", i, state->og.header_len, state->og.body_len)); D2(fprintf(debug_file, "\n%d %ld %ld\n", i, state->og.header_len, state->og.body_len));
return -CAMOGM_FRAME_FILE_ERR; return -CAMOGM_FRAME_FILE_ERR;
} }
} }
//!create comment // create comment
//!use fixed minimal one - hdbuf will be enough for that // use fixed minimal one - hdbuf will be enough for that
memset(hdbuf, 0, sizeof(hdbuf)); memset(hdbuf, 0, sizeof(hdbuf));
hdbuf[0] = PACKET_TYPE_COMMENT; hdbuf[0] = PACKET_TYPE_COMMENT;
memcpy(&hdbuf[1], "vorbis", 6); memcpy(&hdbuf[1], "vorbis", 6);
...@@ -113,7 +102,7 @@ int camogm_start_ogm(camogm_state *state) ...@@ -113,7 +102,7 @@ int camogm_start_ogm(camogm_state *state)
put_uint32(&hdbuf[pos], 0); put_uint32(&hdbuf[pos], 0);
pos += 4; pos += 4;
hdbuf[pos++] = 1; hdbuf[pos++] = 1;
//! put it into Ogg stream // put it into Ogg stream
ogg_header.packet = (unsigned char *)hdbuf; ogg_header.packet = (unsigned char *)hdbuf;
ogg_header.bytes = pos; ogg_header.bytes = pos;
ogg_header.b_o_s = 0; ogg_header.b_o_s = 0;
...@@ -121,35 +110,25 @@ int camogm_start_ogm(camogm_state *state) ...@@ -121,35 +110,25 @@ int camogm_start_ogm(camogm_state *state)
ogg_header.packetno = state->packetno++;; ogg_header.packetno = state->packetno++;;
ogg_header.granulepos = 0; ogg_header.granulepos = 0;
ogg_stream_packetin(&(state->os), &ogg_header); ogg_stream_packetin(&(state->os), &ogg_header);
/* // calculate initial absolute granulepos (from 1970), then increment with each frame. Later try calculating granulepos of each frame
while(ogg_stream_pageout(&(state->os), &(state->og))) { // from the absolute time (actual timestamp)
int i, j;
if ((((i = fwrite(state->og.header, 1, state->og.header_len, state->vf))) != state->og.header_len) ||
(state->og.body_len && (((i = fwrite(state->og.body, 1, state->og.body_len, state->vf))) != state->og.body_len))) {
j=errno;
D(fprintf(debug_file,"\n%d %ld %ld\n",i,state->og.header_len,state->og.body_len));
return -CAMOGM_FRAME_FILE_ERR;
}
}
*/
//! calculate initial absolute granulepos (from 1970), then increment with each frame. Later try calculating granulepos of each frame
//! from the absolute time (actual timestamp)
state->granulepos = (ogg_int64_t)( (((double)state->frame_params[state->port_num].timestamp_usec) + state->granulepos = (ogg_int64_t)( (((double)state->frame_params[state->port_num].timestamp_usec) +
(((double)1000000) * ((double)state->frame_params[state->port_num].timestamp_sec))) * (((double)1000000) * ((double)state->frame_params[state->port_num].timestamp_sec))) *
((double)10) / ((double)10) /
((double)state->time_unit) * ((double)state->time_unit) *
((double)state->timescale)); ((double)state->timescale));
// state->frame_period=(state->this_frame_params.timestamp_usec - state->frame_params.timestamp_usec)+ // temporarily setting granulepos to 0 (suspect they do not process correctly 64 bits)
// 1000000*(state->this_frame_params.timestamp_sec - state->frame_params.timestamp_sec);
// put_uint64(&sh.time_unit, (ogg_int64_t)((double)10000000.0 / (double)fps));
//!Temporarily setting granulepos to 0 (suspect they do not process correctly 64 bits)
state->granulepos = 0; state->granulepos = 0;
//! Here - Ogg stream started, both header and comment packets are sent out, next should be just data packets // Here - Ogg stream started, both header and comment packets are sent out, next should be just data packets
return 0; return 0;
} }
/**
* @brief Write a frame to file
* @param[in] state a pointer to a structure containing current state
* @return 0 if frame was saved successfully and negative error code otherwise
*/
int camogm_frame_ogm(camogm_state *state) int camogm_frame_ogm(camogm_state *state)
{ {
int indx; int indx;
...@@ -158,8 +137,8 @@ int camogm_frame_ogm(camogm_state *state) ...@@ -158,8 +137,8 @@ int camogm_frame_ogm(camogm_state *state)
elp_packet.bytes = 0; elp_packet.bytes = 0;
for (indx = 0; indx < state->chunk_index; indx++) elp_packet.bytes += state->packetchunks[indx].bytes; for (indx = 0; indx < state->chunk_index; indx++) elp_packet.bytes += state->packetchunks[indx].bytes;
elp_packet.packet = state->packetchunks; elp_packet.packet = state->packetchunks;
//D(fprintf (debug_file,"elp_packet.bytes=0x%lx: elp_packet.packet=%p\n",elp_packet.bytes, elp_packet.packet)); //D(fprintf (debug_file,"elp_packet.bytes=0x%lx: elp_packet.packet=%p\n",elp_packet.bytes, elp_packet.packet));
/*D(fprintf (debug_file,"0:0x%lx: %p\n" \ /*D(fprintf (debug_file,"0:0x%lx: %p\n" \
"1:0x%lx: %p\n" \ "1:0x%lx: %p\n" \
"2:0x%lx: %p\n" \ "2:0x%lx: %p\n" \
"3:0x%lx: %p\n" \ "3:0x%lx: %p\n" \
...@@ -173,23 +152,21 @@ int camogm_frame_ogm(camogm_state *state) ...@@ -173,23 +152,21 @@ int camogm_frame_ogm(camogm_state *state)
elp_packet.packet[4].bytes, elp_packet.packet[4].chunk, elp_packet.packet[4].bytes, elp_packet.packet[4].chunk,
elp_packet.packet[5].bytes, elp_packet.packet[5].chunk, elp_packet.packet[5].bytes, elp_packet.packet[5].chunk,
elp_packet.packet[6].bytes, elp_packet.packet[6].chunk)); elp_packet.packet[6].bytes, elp_packet.packet[6].chunk));
*/ */
elp_packet.b_o_s = 0; elp_packet.b_o_s = 0;
elp_packet.e_o_s = 0; elp_packet.e_o_s = 0;
elp_packet.packetno = state->packetno++;; elp_packet.packetno = state->packetno++;;
// tts[0]=state->frame_params.timestamp_usec;
// tts[1]=state->frame_params.timestamp_sec;
elp_packet.granulepos = state->granulepos; elp_packet.granulepos = state->granulepos;
//!TODO: If that works, calculate granulepos from timestamp for each frame /// @todo If that works, calculate granulepos from timestamp for each frame
state->granulepos += (ogg_int64_t)state->timescale; state->granulepos += (ogg_int64_t)state->timescale;
//D3(fprintf (debug_file,"_121_")); //D3(fprintf (debug_file,"_121_"));
ogg_stream_packetin_elph(&(state->os), &elp_packet); ogg_stream_packetin_elph(&(state->os), &elp_packet);
//D3(fprintf (debug_file,"_13_")); //D3(fprintf (debug_file,"_13_"));
while (ogg_stream_pageout(&(state->os), &(state->og))) { while (ogg_stream_pageout(&(state->os), &(state->og))) {
int i, j; int i, j;
if ((((i = fwrite(state->og.header, 1, state->og.header_len, state->vf))) != state->og.header_len) || if ((((i = fwrite(state->og.header, 1, state->og.header_len, state->vf))) != state->og.header_len) ||
(state->og.body_len && (((i = fwrite(state->og.body, 1, state->og.body_len, state->vf))) != state->og.body_len))) { (state->og.body_len && (((i = fwrite(state->og.body, 1, state->og.body_len, state->vf))) != state->og.body_len))) {
j = errno; j = errno;
D0(fprintf(debug_file, "\n%d %ld %ld\n", i, state->og.header_len, state->og.body_len)); D0(fprintf(debug_file, "\n%d %ld %ld\n", i, state->og.header_len, state->og.body_len));
return -CAMOGM_FRAME_FILE_ERR; return -CAMOGM_FRAME_FILE_ERR;
...@@ -198,11 +175,15 @@ int camogm_frame_ogm(camogm_state *state) ...@@ -198,11 +175,15 @@ int camogm_frame_ogm(camogm_state *state)
return 0; return 0;
} }
//!Zero packets are OK, use them to end file with "last" turned on /**
* @brief Finish OGM file operation
* @param[in] state a pointer to a structure containing current state
* @return 0 if file was saved successfully and negative error code otherwise
* @note: zero packets are OK, use them to end file with "last" turned on
*/
int camogm_end_ogm(camogm_state *state) int camogm_end_ogm(camogm_state *state)
{ {
//! put zero-packet it into stream // put zero-packet it into stream
ogg_packet ogg_header; ogg_packet ogg_header;
ogg_header.packet = NULL; ogg_header.packet = NULL;
...@@ -211,11 +192,11 @@ int camogm_end_ogm(camogm_state *state) ...@@ -211,11 +192,11 @@ int camogm_end_ogm(camogm_state *state)
ogg_header.e_o_s = 1; ogg_header.e_o_s = 1;
ogg_header.packetno = state->packetno++; ogg_header.packetno = state->packetno++;
ogg_header.granulepos = ++(state->granulepos); ogg_header.granulepos = ++(state->granulepos);
ogg_stream_packetin(&(state->os), &ogg_header); //!+++++++++++++++++++++++++++++++++++++++++++++++++++++ ogg_stream_packetin(&(state->os), &ogg_header); // +++++++++++++++++++++++++++++++++++++++++++++++++++++
while (ogg_stream_flush(&(state->os), &(state->og))) { while (ogg_stream_flush(&(state->os), &(state->og))) {
int i, j; int i, j;
if ((((i = fwrite(state->og.header, 1, state->og.header_len, state->vf))) != state->og.header_len) || if ((((i = fwrite(state->og.header, 1, state->og.header_len, state->vf))) != state->og.header_len) ||
(state->og.body_len && (((i = fwrite(state->og.body, 1, state->og.body_len, state->vf))) != state->og.body_len))) { (state->og.body_len && (((i = fwrite(state->og.body, 1, state->og.body_len, state->vf))) != state->og.body_len))) {
j = errno; j = errno;
D0(fprintf(debug_file, "\n%d %ld %ld\n", i, state->og.header_len, state->og.body_len)); D0(fprintf(debug_file, "\n%d %ld %ld\n", i, state->og.header_len, state->og.body_len));
return -CAMOGM_FRAME_FILE_ERR; return -CAMOGM_FRAME_FILE_ERR;
......
/** @file camogm_ogm.h
* @brief Provides writing to OGM files for @e camogm
* @copyright Copyright (C) 2016 Elphel, Inc.
*
* @par <b>License</b>
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _CAMOGM_OGM_H #ifndef _CAMOGM_OGM_H
#define _CAMOGM_OGM_H #define _CAMOGM_OGM_H
......
...@@ -305,6 +305,18 @@ static int find_marker(const unsigned char * restrict buff_ptr, ssize_t buff_sz, ...@@ -305,6 +305,18 @@ static int find_marker(const unsigned char * restrict buff_ptr, ssize_t buff_sz,
return ret; return ret;
} }
/**
* @brief Find pattern in a data buffer in reverse order
*
* This function searches for the first occurrence of pattern in a data buffer and returns a pointer to
* the position of this pattern in the buffer.
* @param[in] buff_ptr pointer to an array of char values where the pattern should be found
* @param[in] buff_sz size of the data array
* @param[in] pattern pointer to an array of char values containing pattern
* @param[in] pt_sz size of the pattern array
* @param[in] add_pattern include or exclude marker from resulting buffer offset
* @return The index in data buffer where pattern matches or error code from #match_result if it was not found
*/
static int find_marker_backward(const unsigned char * restrict buff_ptr, ssize_t buff_sz, const unsigned char * restrict pattern, ssize_t pt_sz, static int find_marker_backward(const unsigned char * restrict buff_ptr, ssize_t buff_sz, const unsigned char * restrict pattern, ssize_t pt_sz,
int add_pattern) int add_pattern)
{ {
......
...@@ -63,6 +63,12 @@ int add_node(struct disk_idir *idir, struct disk_index *index) ...@@ -63,6 +63,12 @@ int add_node(struct disk_idir *idir, struct disk_index *index)
return idir->size; return idir->size;
} }
/**
* @brief Insert new node in chronological order
* @param[in,out] idir index directory to which a new node should be added
* @param[in] indx a pointer to new node
* @return The number of nodes in the directory
*/
int insert_node(struct disk_idir *idir, struct disk_index *indx) int insert_node(struct disk_idir *idir, struct disk_index *indx)
{ {
int ret = 0; int ret = 0;
...@@ -157,6 +163,11 @@ struct disk_index *find_by_offset(const struct disk_idir *idir, uint64_t offset) ...@@ -157,6 +163,11 @@ struct disk_index *find_by_offset(const struct disk_idir *idir, uint64_t offset)
return index; return index;
} }
/** @brief Find index node by its time stamp
* @param[in] idir pointer to disk index directory
* @param[in] time the time stamp of the file which should be found
* @return pointer to disk index node or NULL if the corresponding file was not found
*/
struct disk_index *find_nearest_by_time(const struct disk_idir *idir, time_t time) struct disk_index *find_nearest_by_time(const struct disk_idir *idir, time_t time)
{ {
struct disk_index *ptr = NULL; struct disk_index *ptr = NULL;
......
/** @file ogmstreams.h */
#ifndef __OGGSTREAMS_H #ifndef __OGGSTREAMS_H
#define __OGGSTREAMS_H #define __OGGSTREAMS_H
/* /**
* Taken from http://tobias.everwicked.com/packfmt.htm * Taken from http://tobias.everwicked.com/packfmt.htm
* *
First packet (header)
---------------------
pos | content | description
-------+-------------------------+----------------------------------
0x0000 | 0x01 | indicates 'header packet'
-------+-------------------------+----------------------------------
0x0001 | stream_header | the size is indicated in the
| | size member
Second packet (comment)
-----------------------
pos | content | description
-------+-------------------------+----------------------------------
0x0000 | 0x03 | indicates 'comment packet'
-------+-------------------------+----------------------------------
0x0001 | data | see vorbis doc on www.xiph.org
Data packets
------------
pos | content | description
---------+-------------------------+----------------------------------
0x0000 | Bit0 0 | indicates data packet
| Bit1 Bit 2 of lenbytes |
| Bit2 unused |
| Bit3 keyframe |
| Bit4 unused |
| Bit5 unused |
| Bit6 Bit 0 of lenbytes |
| Bit7 Bit 1 of lenbytes |
---------+-------------------------+----------------------------------
0x0001 | LowByte | Length of this packet in samples
| ... | (frames for video, samples for
| HighByte | audio, 1ms units for text)
---------+-------------------------+----------------------------------
0x0001+ | data | packet contents
lenbytes | |
* *
* First packet (header)
* ---------------------
*
* pos | content | description
* -------|-------------------------|----------------------------------
* 0x0000 | 0x01 | indicates 'header packet'
* 0x0001 | stream_header | the size is indicated in the
* &nbsp; | &nbsp; | size member
*
*
* Second packet (comment)
* -----------------------
*
* pos | content | description
* -------|-------------------------|----------------------------------
* 0x0000 | 0x03 | indicates 'comment packet'
* 0x0001 | data | see vorbis doc on www.xiph.org
*
*
* Data packets
* ------------
*
* pos | content | description
* ---------|-------------------------|----------------------------------
* 0x0000 | Bit0 0 | indicates data packet
* &nbsp; | Bit1 Bit 2 of lenbytes | &nbsp;
* &nbsp; | Bit2 unused | &nbsp;
* &nbsp; | Bit3 keyframe | &nbsp;
* &nbsp; | Bit4 unused | &nbsp;
* &nbsp; | Bit5 unused | &nbsp;
* &nbsp; | Bit6 Bit 0 of lenbytes | &nbsp;
* &nbsp; | Bit7 Bit 1 of lenbytes | &nbsp;
* 0x0001 | LowByte | Length of this packet in samples
* &nbsp; | ... | (frames for video, samples for
* &nbsp; | HighByte | audio, 1ms units for text)
* 0x0001+ | data | packet contents
* lenbytes | &nbsp; | &nbsp;
* *
*/ */
//// OggDS headers /** OggDS headers */
// Header for the new header format /** Header for the new header format */
typedef struct stream_header_video { typedef struct stream_header_video {
ogg_int32_t width; ogg_int32_t width;
ogg_int32_t height; ogg_int32_t height;
...@@ -121,4 +117,4 @@ typedef struct old_stream_header { ...@@ -121,4 +117,4 @@ typedef struct old_stream_header {
#define PACKET_LEN_BITS2 0x02 #define PACKET_LEN_BITS2 0x02
#define PACKET_IS_SYNCPOINT 0x08 #define PACKET_IS_SYNCPOINT 0x08
#endif /* __OGGSTREAMS_H */ #endif /* __OGGSTREAMS_H */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment