apps/camogm2/camogm_ogm.c

Go to the documentation of this file.
00001 /*!***************************************************************************
00002 *! FILE NAME  : camogm_ogm.c
00003 *! DESCRIPTION: Provides writing to ogm files for camogm
00004 *! Copyright (C) 2007 Elphel, Inc.
00005 *! -----------------------------------------------------------------------------**
00006 *!  This program is free software: you can redistribute it and/or modify
00007 *!  it under the terms of the GNU General Public License as published by
00008 *!  the Free Software Foundation, either version 3 of the License, or
00009 *!  (at your option) any later version.
00010 *!
00011 *!  This program is distributed in the hope that it will be useful,
00012 *!  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 *!  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 *!  GNU General Public License for more details.
00015 *!
00016 *!  You should have received a copy of the GNU General Public License
00017 *!  along with this program.  If not, see <http://www.gnu.org/licenses/>.
00018 *! -----------------------------------------------------------------------------**
00019 *!
00020 *!  $Log: camogm_ogm.c,v $
00021 *!  Revision 1.1.1.1  2008/11/27 20:04:01  elphel
00022 *!
00023 *!
00024 *!  Revision 1.1  2008/05/02 12:45:58  spectr_rain
00025 *!  initial revision with the sound support
00026 *!
00027 *!  Revision 1.2  2007/11/19 03:23:21  elphel
00028 *!  7.1.5.5 Added support for *.mov files in camogm.
00029 *!
00030 *!  Revision 1.1  2007/11/16 08:49:58  elphel
00031 *!  Initial release of camogm - program to record video/image to the camera hard drive (or other storage)
00032 *!
00033 */
00035 #include <unistd.h>
00036 #include <stdio.h>
00037 #include <stdlib.h>
00038 #include <signal.h>
00039 #include <fcntl.h>
00040 #include <sys/uio.h>
00041 #include <errno.h>
00042 #include <sys/types.h>
00043 #include <sys/socket.h>
00044 #include <sys/stat.h>
00045 //#include <ctype.h>
00046 //#include <getopt.h>
00047 #include <time.h>
00048 #include <string.h>
00049 
00050 #include <netinet/in.h> /*little <-> big endian ?*/
00051 #include <sys/mman.h>           /* mmap */
00052 #include <sys/ioctl.h>
00053 
00054 #include <asm/elphel/c313a.h>
00055 #include <asm/elphel/ext353.h>
00056 #include <asm/byteorder.h>
00057 
00058 
00059 #include <ogg/ogg.h> // has to be before ogmstreams.h
00060 #include "ogmstreams.h" // move it to <>?
00061 
00062 #include "camogm_ogm.h"
00063 #include "camogm.h"
00064 
00065 struct ogm_stream_t {
00066         ogg_stream_state os;
00067         ogg_page og;
00068         ogg_packet op;
00069         elph_ogg_packet eop;
00070         ogg_int64_t packetno;
00071         ogg_int64_t granulepos;
00072 };
00073 
00074 struct ogm_stream_t svideo;
00075 struct ogm_stream_t saudio;
00076 
00077 int ogm_flush_to_file(struct ogm_stream_t *stream) {
00078         int i, j;
00079         while(ogg_stream_flush(&(stream->os), &(stream->og))) {
00080                 if((((i = fwrite(stream->og.header, 1, stream->og.header_len, state->vf))) != stream->og.header_len) || (stream->og.body_len && (((i = fwrite(stream->og.body, 1, stream->og.body_len, state->vf))) != stream->og.body_len))) {
00081                         j = errno;
00082                         D2(fprintf(debug_file, "\nogm_flush_to_file() fail: %d %ld %ld\n", i, stream->og.header_len, stream->og.body_len));
00083                         return -CAMOGM_FRAME_FILE_ERR;
00084                 }
00085         }
00086         return 0;
00087 }
00088 
00089 // audio
00090 int camogm_audio_init(void);
00091 int camogm_audio_end(void);
00092 
00094 int camogm_init_ogm(void) {
00095         return 0;
00096 }
00097 
00098 void camogm_free_ogm(void) {
00099 }
00100 
00101 int camogm_start_ogm(void) {
00102         char vendor[]= "CamOGM";
00103         int pos;
00104         int rez = 0;
00105         stream_header sh;
00106         char hdbuf[sizeof(stream_header) + 1];
00107         ogg_packet ogg_header;
00108         sprintf(state->path, "%s%010ld_%06ld.ogm", state->path_prefix, state->frame_params.timestamp_sec, state->frame_params.timestamp_usec);
00109         if(!((state->vf = fopen(state->path, "w+")))) {
00110                 D0(fprintf(debug_file, "Error opening %s for writing\n", state->path));
00111                 return -CAMOGM_FRAME_FILE_ERR;
00112         }
00113         ogg_stream_init(&(svideo.os), state->serialno);
00114         svideo.packetno = 0;
00115         // make video header
00116         memset(&sh, 0, sizeof(sh));
00117         memcpy(sh.streamtype, "video", 5);
00118         memcpy(sh.subtype, "MJPG", 4);
00119         put_uint32(&sh.size, sizeof(stream_header));
00120 //      put_uint64(&sh.time_unit, (ogg_int64_t) 10*state->frame_period);
00121         put_uint64(&sh.time_unit, state->time_unit);
00122 //fprintf(stderr, "time_unit == %d\n", state->time_unit);
00123 //      put_uint64(&sh.samples_per_unit, 1);
00124 //state->timescale = 1;
00125         put_uint64(&sh.samples_per_unit, (ogg_int64_t)state->timescale);
00126 //      put_uint64(&sh.samples_per_unit, (ogg_int64_t)1);
00127 //fprintf(stderr, "__samples_per_unit == %d\n", (int)state->timescale);
00128         put_uint32(&sh.default_len, 1);
00129         put_uint32(&sh.buffersize, state->width * state->height);
00130 //   put_uint16(&sh.bits_per_sample, 24); //?
00131         put_uint16(&sh.bits_per_sample, 0); //?
00132         put_uint32(&sh.sh.video.width, state->width);
00133         put_uint32(&sh.sh.video.height, state->height);
00134         memcpy(&hdbuf[1], &sh, sizeof(sh));
00135         hdbuf[0] = 1;
00137         ogg_header.packet = hdbuf;
00138         ogg_header.bytes = sizeof(sh) + 1;
00139         ogg_header.b_o_s = 1;
00140         ogg_header.e_o_s = 0;
00141         ogg_header.packetno = svideo.packetno++;;
00142         ogg_header.granulepos = 0;
00143         ogg_stream_packetin(&svideo.os, &ogg_header);
00144 
00145         if((rez = ogm_flush_to_file(&svideo)) != 0)
00146                 return rez;
00147 
00150         memset(hdbuf, 0, sizeof(hdbuf));
00151         hdbuf[0] = PACKET_TYPE_COMMENT;
00152         memcpy(&hdbuf[1], "vorbis", 6);
00153         pos = 7;
00154         put_uint32(&hdbuf[pos], strlen(vendor));
00155         pos += 4;
00156         strcpy(&hdbuf[pos], vendor);
00157         pos += strlen(vendor);
00158         put_uint32(&hdbuf[pos], 0);
00159         pos += 4;
00160         hdbuf[pos++] = 1;
00162         ogg_header.packet = hdbuf;
00163         ogg_header.bytes = pos;
00164         ogg_header.b_o_s = 0;
00165         ogg_header.e_o_s = 0;
00166         ogg_header.packetno = svideo.packetno++;;
00167         ogg_header.granulepos = 0;
00168         ogg_stream_packetin(&svideo.os, &ogg_header);
00171 //      state->granulepos = (ogg_int64_t)((((double) state->frame_params.timestamp_usec) +
00172         svideo.granulepos = (ogg_int64_t)((((double) state->frame_params.timestamp_usec) +
00173                                     (((double) 1000000) * ((double)state->frame_params.timestamp_sec))) *
00174                                     ((double) 10) /
00175                                     ((double) state->time_unit) *
00176                                     ((double) state->timescale));
00177 //   state->frame_period=(state->this_frame_params.timestamp_usec - state->frame_params.timestamp_usec)+
00178 //               1000000*(state->this_frame_params.timestamp_sec  - state->frame_params.timestamp_sec);
00179 //  put_uint64(&sh.time_unit, (ogg_int64_t)((double)10000000.0 / (double)fps));
00180 
00182         svideo.granulepos = 0;
00183 
00185         rez = 0;
00186         if(state->audio_enable)
00187                 rez = camogm_audio_init();
00188         return rez;
00189 }
00190 
00191 int camogm_frame_ogm(void){
00192         int indx;
00193         int rez;
00194 
00195         elph_ogg_packet elp_packet;
00196         elp_packet.bytes = 0;
00197         for(indx = 0; indx < state->chunk_index; indx++)
00198                 elp_packet.bytes += state->packetchunks[indx].bytes;
00199         elp_packet.packet = state->packetchunks;
00200 /*D(fprintf (debug_file,"0:0x%lx: %p\n" \
00201                              "1:0x%lx: %p\n" \
00202                              "2:0x%lx: %p\n" \
00203                              "3:0x%lx: %p\n" \
00204                              "4:0x%lx: %p\n" \
00205                              "5:0x%lx: %p\n" \
00206                              "6:0x%lx: %p\n", \
00207                               elp_packet.packet[0].bytes,  elp_packet.packet[0].chunk,
00208                               elp_packet.packet[1].bytes,  elp_packet.packet[1].chunk,
00209                               elp_packet.packet[2].bytes,  elp_packet.packet[2].chunk,
00210                               elp_packet.packet[3].bytes,  elp_packet.packet[3].chunk,
00211                               elp_packet.packet[4].bytes,  elp_packet.packet[4].chunk,
00212                               elp_packet.packet[5].bytes,  elp_packet.packet[5].chunk,
00213                               elp_packet.packet[6].bytes,  elp_packet.packet[6].chunk));
00214 */
00215         elp_packet.b_o_s = 0;
00216         elp_packet.e_o_s = 0;
00217         elp_packet.packetno = svideo.packetno++;;
00218 //      tts[0]=state->frame_params.timestamp_usec;
00219 //      tts[1]=state->frame_params.timestamp_sec;
00220 //      elp_packet.granulepos = state->granulepos;
00221         elp_packet.granulepos = svideo.granulepos;
00223 //      state->granulepos += (ogg_int64_t)state->timescale;
00224         svideo.granulepos += (ogg_int64_t)state->timescale;
00225 
00226         ogg_stream_packetin_elph(&svideo.os, &elp_packet);
00227         if((rez = ogm_flush_to_file(&svideo)) != 0)
00228                 return rez;
00229 //      fflush(state->vf);
00230         if(state->allow_sync)
00231                 sync();
00232         return 0;
00233 }
00234 
00235 int camogm_end_ogm(void){
00236         int rez = 0;
00237         ogg_packet ogg_header;
00238         char buf[1] = {0x00};
00239 
00240         ogg_header.packet = buf;
00241         ogg_header.bytes = 1;
00242         ogg_header.b_o_s = 0;
00243         ogg_header.e_o_s = 1;
00244         ogg_header.packetno = svideo.packetno++;
00245         ogg_header.granulepos = ++(svideo.granulepos);
00246         ogg_stream_packetin(&svideo.os, &ogg_header);
00247 
00248         if((rez = ogm_flush_to_file(&svideo)) != 0)
00249                 return rez;
00250         rez = 0;
00251         if(state->audio_enable)
00252                 rez = camogm_audio_end();
00253         return rez;
00254 }
00255 
00256 int camogm_audio_init(void) {
00257         char vendor[]= "CamOGM";
00258         char hdbuf[sizeof(stream_header) + 1];
00259         int pos;
00260         int rez;
00261 
00262         stream_header sh_audio;
00263         ogg_packet ogg_header;
00264 
00265         saudio.packetno = 0;
00266         saudio.granulepos = 0;
00267         // make audio header
00268         ogg_stream_init(&saudio.os, 0x28);
00269         saudio.packetno = 0;
00270         memset(&sh_audio, 0, sizeof(stream_header));
00271         memcpy(sh_audio.streamtype, "audio", 5);
00272         memcpy(sh_audio.subtype, "0001", 4);
00273         put_uint32(&sh_audio.size, sizeof(stream_header));
00274         put_uint64(&sh_audio.time_unit, 1000);
00275         put_uint64(&sh_audio.samples_per_unit, (ogg_int64_t)state->audio_rate);
00276         put_uint32(&sh_audio.default_len, 0);
00277         put_uint32(&sh_audio.buffersize, 0);
00278         put_uint16(&sh_audio.bits_per_sample, 16);
00279         put_uint32(&sh_audio.sh.audio.channels, state->audio_channels);
00280         put_uint32(&sh_audio.sh.audio.blockalign, 1);
00281         put_uint32(&sh_audio.sh.audio.avgbytespersec, state->audio_channels * state->audio_rate * 2);   // 16 bits
00282         memcpy(&hdbuf[1], &sh_audio, sizeof(sh_audio));
00283         hdbuf[0] = 1;
00284 
00286         ogg_header.packet = hdbuf;
00287         ogg_header.bytes = sizeof(sh_audio) + 1;
00288         ogg_header.b_o_s = 1;
00289         ogg_header.e_o_s = 0;
00290         ogg_header.packetno = saudio.packetno++;
00291         ogg_header.granulepos = 0;
00292         ogg_stream_packetin(&saudio.os, &ogg_header);
00293 
00294         if((rez = ogm_flush_to_file(&saudio)) != 0)
00295                 return rez;
00298         memset(hdbuf, 0, sizeof(hdbuf));
00299         hdbuf[0] = PACKET_TYPE_COMMENT;
00300         memcpy(&hdbuf[1], "vorbis", 6);
00301         pos=7;
00302         put_uint32(&hdbuf[pos], strlen(vendor));
00303         pos += 4;
00304         strcpy(&hdbuf[pos], vendor);
00305         pos += strlen(vendor);
00306         put_uint32(&hdbuf[pos], 0);
00307         pos += 4;
00308         hdbuf[pos++] = 1;
00310         ogg_header.packet = hdbuf;
00311         ogg_header.bytes = pos;
00312         ogg_header.b_o_s = 0;
00313         ogg_header.e_o_s = 0;
00314         ogg_header.packetno = saudio.packetno++;;
00315         ogg_header.granulepos = 0;
00316         ogg_stream_packetin(&saudio.os, &ogg_header);
00317 
00318         if((rez = ogm_flush_to_file(&saudio)) != 0)
00319                 return rez;
00320         return 0;
00321 }
00322 
00323 int camogm_audio_end(void) {
00324         ogg_packet ogg_header;
00325         int rez;
00326         char buf[1] = {0x00};
00327 
00328         ogg_header.packet = buf;
00329         ogg_header.bytes = 1;
00330         ogg_header.b_o_s = 0;
00331         ogg_header.e_o_s = 1;
00332         ogg_header.packetno = saudio.packetno++;
00333         ogg_header.granulepos = saudio.granulepos;
00334         ogg_stream_packetin(&saudio.os, &ogg_header);
00335         if((rez = ogm_flush_to_file(&saudio)) != 0)
00336                 return rez;
00337         return 0;
00338 }
00339 
00340 void camogm_audio_ogm_push(void *buf, int len, long granules_shift, int prefix) {
00341         u_int16_t samp_in_subpacket = granules_shift;
00342         unsigned char *h = (unsigned char *)buf - (1 + sizeof(samp_in_subpacket));
00343         int j;
00344         int rez;
00345         
00346         h[0] = 0x00;
00347         h[0] = ((sizeof(samp_in_subpacket) & 3) << 6) + ((sizeof(samp_in_subpacket) & 4) >> 1);
00348         h[0] |= PACKET_IS_SYNCPOINT;
00349         for(j = 0; j < sizeof(samp_in_subpacket); j++) {
00350                 h[j + 1] = (unsigned char)(samp_in_subpacket & 0xFF);
00351                 samp_in_subpacket = samp_in_subpacket >> 8;
00352         }
00353         ogg_packet packet;
00354         packet.bytes = len + 1 + sizeof(samp_in_subpacket);
00355         packet.packet = (char *)h;
00356         packet.b_o_s = 0;
00357         packet.e_o_s = 0;
00358         packet.packetno = saudio.packetno++;;
00359         packet.granulepos = saudio.granulepos;
00360         saudio.granulepos += (ogg_int64_t)granules_shift;
00361         ogg_stream_packetin(&saudio.os, &packet);
00362         rez = ogm_flush_to_file(&saudio);
00363 }

Generated on Fri Nov 28 00:06:21 2008 for elphel by  doxygen 1.5.1