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.2  2008/05/23 13:09:49  spectr_rain
00022 *!  QuickTime support
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                 if((((i = write(state->vf, stream->og.header, stream->og.header_len))) != stream->og.header_len) || (stream->og.body_len && (((i = write(state->vf, stream->og.body, stream->og.body_len))) != stream->og.body_len))) {
00082                         j = errno;
00083                         D2(fprintf(debug_file, "\nogm_flush_to_file() fail: %d %ld %ld\n", i, stream->og.header_len, stream->og.body_len));
00084                         return -CAMOGM_FRAME_FILE_ERR;
00085                 }
00086         }
00087         return 0;
00088 }
00089 
00090 // audio
00091 int camogm_audio_init(void);
00092 int camogm_audio_end(void);
00093 
00095 int camogm_init_ogm(void) {
00096         return 0;
00097 }
00098 
00099 void camogm_free_ogm(void) {
00100 }
00101 
00102 int camogm_start_ogm(void) {
00103         char vendor[]= "CamOGM";
00104         int pos;
00105         int rez = 0;
00106         stream_header sh;
00107         char hdbuf[sizeof(stream_header) + 1];
00108         ogg_packet ogg_header;
00109         sprintf(state->path, "%s%010ld_%06ld.ogm", state->path_prefix, state->frame_params.timestamp_sec, state->frame_params.timestamp_usec);
00110 /*
00111         if(!((state->vf = fopen(state->path, "w+")))) {
00112                 D0(fprintf(debug_file, "Error opening %s for writing\n", state->path));
00113                 return -CAMOGM_FRAME_FILE_ERR;
00114         }
00115 */
00116         if(!((state->vf = open(state->path, O_RDWR | O_CREAT)))) {
00117                 D0(fprintf(debug_file, "Error opening %s for writing\n", state->path));
00118                 return -CAMOGM_FRAME_FILE_ERR;
00119         }
00120         ogg_stream_init(&(svideo.os), state->serialno);
00121         svideo.packetno = 0;
00122         // make video header
00123         memset(&sh, 0, sizeof(sh));
00124         memcpy(sh.streamtype, "video", 5);
00125         memcpy(sh.subtype, "MJPG", 4);
00126         put_uint32(&sh.size, sizeof(stream_header));
00127 //      put_uint64(&sh.time_unit, (ogg_int64_t) 10*state->frame_period);
00128         put_uint64(&sh.time_unit, state->time_unit);
00129 //fprintf(stderr, "time_unit == %d\n", state->time_unit);
00130 //      put_uint64(&sh.samples_per_unit, 1);
00131 //state->timescale = 1;
00132         put_uint64(&sh.samples_per_unit, (ogg_int64_t)state->timescale);
00133 //      put_uint64(&sh.samples_per_unit, (ogg_int64_t)1);
00134 //fprintf(stderr, "__samples_per_unit == %d\n", (int)state->timescale);
00135         put_uint32(&sh.default_len, 1);
00136         put_uint32(&sh.buffersize, state->width * state->height);
00137 //   put_uint16(&sh.bits_per_sample, 24); //?
00138         put_uint16(&sh.bits_per_sample, 0); //?
00139         put_uint32(&sh.sh.video.width, state->width);
00140         put_uint32(&sh.sh.video.height, state->height);
00141         memcpy(&hdbuf[1], &sh, sizeof(sh));
00142         hdbuf[0] = 1;
00144         ogg_header.packet = hdbuf;
00145         ogg_header.bytes = sizeof(sh) + 1;
00146         ogg_header.b_o_s = 1;
00147         ogg_header.e_o_s = 0;
00148         ogg_header.packetno = svideo.packetno++;;
00149         ogg_header.granulepos = 0;
00150         ogg_stream_packetin(&svideo.os, &ogg_header);
00151 
00152         if((rez = ogm_flush_to_file(&svideo)) != 0)
00153                 return rez;
00154 
00157         memset(hdbuf, 0, sizeof(hdbuf));
00158         hdbuf[0] = PACKET_TYPE_COMMENT;
00159         memcpy(&hdbuf[1], "vorbis", 6);
00160         pos = 7;
00161         put_uint32(&hdbuf[pos], strlen(vendor));
00162         pos += 4;
00163         strcpy(&hdbuf[pos], vendor);
00164         pos += strlen(vendor);
00165         put_uint32(&hdbuf[pos], 0);
00166         pos += 4;
00167         hdbuf[pos++] = 1;
00169         ogg_header.packet = hdbuf;
00170         ogg_header.bytes = pos;
00171         ogg_header.b_o_s = 0;
00172         ogg_header.e_o_s = 0;
00173         ogg_header.packetno = svideo.packetno++;;
00174         ogg_header.granulepos = 0;
00175         ogg_stream_packetin(&svideo.os, &ogg_header);
00178 //      state->granulepos = (ogg_int64_t)((((double) state->frame_params.timestamp_usec) +
00179         svideo.granulepos = (ogg_int64_t)((((double) state->frame_params.timestamp_usec) +
00180                                     (((double) 1000000) * ((double)state->frame_params.timestamp_sec))) *
00181                                     ((double) 10) /
00182                                     ((double) state->time_unit) *
00183                                     ((double) state->timescale));
00184 //   state->frame_period=(state->this_frame_params.timestamp_usec - state->frame_params.timestamp_usec)+
00185 //               1000000*(state->this_frame_params.timestamp_sec  - state->frame_params.timestamp_sec);
00186 //  put_uint64(&sh.time_unit, (ogg_int64_t)((double)10000000.0 / (double)fps));
00187 
00189         svideo.granulepos = 0;
00190 
00192         rez = 0;
00193         if(state->audio_enable)
00194                 rez = camogm_audio_init();
00195         return rez;
00196 }
00197 
00198 int camogm_frame_ogm(void){
00199         int indx;
00200         int rez;
00201 
00202         elph_ogg_packet elp_packet;
00203         elp_packet.bytes = 0;
00204         for(indx = 0; indx < state->chunk_index; indx++)
00205                 elp_packet.bytes += state->packetchunks[indx].bytes;
00206         elp_packet.packet = state->packetchunks;
00207 /*D(fprintf (debug_file,"0:0x%lx: %p\n" \
00208                              "1:0x%lx: %p\n" \
00209                              "2:0x%lx: %p\n" \
00210                              "3:0x%lx: %p\n" \
00211                              "4:0x%lx: %p\n" \
00212                              "5:0x%lx: %p\n" \
00213                              "6:0x%lx: %p\n", \
00214                               elp_packet.packet[0].bytes,  elp_packet.packet[0].chunk,
00215                               elp_packet.packet[1].bytes,  elp_packet.packet[1].chunk,
00216                               elp_packet.packet[2].bytes,  elp_packet.packet[2].chunk,
00217                               elp_packet.packet[3].bytes,  elp_packet.packet[3].chunk,
00218                               elp_packet.packet[4].bytes,  elp_packet.packet[4].chunk,
00219                               elp_packet.packet[5].bytes,  elp_packet.packet[5].chunk,
00220                               elp_packet.packet[6].bytes,  elp_packet.packet[6].chunk));
00221 */
00222         elp_packet.b_o_s = 0;
00223         elp_packet.e_o_s = 0;
00224         elp_packet.packetno = svideo.packetno++;;
00225 //      tts[0]=state->frame_params.timestamp_usec;
00226 //      tts[1]=state->frame_params.timestamp_sec;
00227 //      elp_packet.granulepos = state->granulepos;
00228         elp_packet.granulepos = svideo.granulepos;
00230 //      state->granulepos += (ogg_int64_t)state->timescale;
00231         svideo.granulepos += (ogg_int64_t)state->timescale;
00232 
00233         ogg_stream_packetin_elph(&svideo.os, &elp_packet);
00234         if((rez = ogm_flush_to_file(&svideo)) != 0)
00235                 return rez;
00236 //      fflush(state->vf);
00237         if(state->allow_sync)
00238                 sync();
00239         return 0;
00240 }
00241 
00242 int camogm_end_ogm(void){
00243         int rez = 0;
00244         ogg_packet ogg_header;
00245         char buf[1] = {0x00};
00246 
00247         ogg_header.packet = buf;
00248         ogg_header.bytes = 1;
00249         ogg_header.b_o_s = 0;
00250         ogg_header.e_o_s = 1;
00251         ogg_header.packetno = svideo.packetno++;
00252         ogg_header.granulepos = ++(svideo.granulepos);
00253         ogg_stream_packetin(&svideo.os, &ogg_header);
00254 
00255         if((rez = ogm_flush_to_file(&svideo)) != 0)
00256                 return rez;
00257         rez = 0;
00258         if(state->audio_enable)
00259                 rez = camogm_audio_end();
00260         return rez;
00261 }
00262 
00263 int camogm_audio_init(void) {
00264         char vendor[]= "CamOGM";
00265         char hdbuf[sizeof(stream_header) + 1];
00266         int pos;
00267         int rez;
00268 
00269         stream_header sh_audio;
00270         ogg_packet ogg_header;
00271 
00272         saudio.packetno = 0;
00273         saudio.granulepos = 0;
00274         // make audio header
00275         ogg_stream_init(&saudio.os, 0x28);
00276         saudio.packetno = 0;
00277         memset(&sh_audio, 0, sizeof(stream_header));
00278         memcpy(sh_audio.streamtype, "audio", 5);
00279         memcpy(sh_audio.subtype, "0001", 4);
00280         put_uint32(&sh_audio.size, sizeof(stream_header));
00281         put_uint64(&sh_audio.time_unit, 1000);
00282         put_uint64(&sh_audio.samples_per_unit, (ogg_int64_t)state->audio_rate);
00283         put_uint32(&sh_audio.default_len, 0);
00284         put_uint32(&sh_audio.buffersize, 0);
00285         put_uint16(&sh_audio.bits_per_sample, 16);
00286         put_uint32(&sh_audio.sh.audio.channels, state->audio_channels);
00287         put_uint32(&sh_audio.sh.audio.blockalign, 1);
00288         put_uint32(&sh_audio.sh.audio.avgbytespersec, state->audio_channels * state->audio_rate * 2);   // 16 bits
00289         memcpy(&hdbuf[1], &sh_audio, sizeof(sh_audio));
00290         hdbuf[0] = 1;
00291 
00293         ogg_header.packet = hdbuf;
00294         ogg_header.bytes = sizeof(sh_audio) + 1;
00295         ogg_header.b_o_s = 1;
00296         ogg_header.e_o_s = 0;
00297         ogg_header.packetno = saudio.packetno++;
00298         ogg_header.granulepos = 0;
00299         ogg_stream_packetin(&saudio.os, &ogg_header);
00300 
00301         if((rez = ogm_flush_to_file(&saudio)) != 0)
00302                 return rez;
00305         memset(hdbuf, 0, sizeof(hdbuf));
00306         hdbuf[0] = PACKET_TYPE_COMMENT;
00307         memcpy(&hdbuf[1], "vorbis", 6);
00308         pos=7;
00309         put_uint32(&hdbuf[pos], strlen(vendor));
00310         pos += 4;
00311         strcpy(&hdbuf[pos], vendor);
00312         pos += strlen(vendor);
00313         put_uint32(&hdbuf[pos], 0);
00314         pos += 4;
00315         hdbuf[pos++] = 1;
00317         ogg_header.packet = hdbuf;
00318         ogg_header.bytes = pos;
00319         ogg_header.b_o_s = 0;
00320         ogg_header.e_o_s = 0;
00321         ogg_header.packetno = saudio.packetno++;;
00322         ogg_header.granulepos = 0;
00323         ogg_stream_packetin(&saudio.os, &ogg_header);
00324 
00325         if((rez = ogm_flush_to_file(&saudio)) != 0)
00326                 return rez;
00327         return 0;
00328 }
00329 
00330 int camogm_audio_end(void) {
00331         ogg_packet ogg_header;
00332         int rez;
00333         char buf[1] = {0x00};
00334 
00335         ogg_header.packet = buf;
00336         ogg_header.bytes = 1;
00337         ogg_header.b_o_s = 0;
00338         ogg_header.e_o_s = 1;
00339         ogg_header.packetno = saudio.packetno++;
00340         ogg_header.granulepos = saudio.granulepos;
00341         ogg_stream_packetin(&saudio.os, &ogg_header);
00342         if((rez = ogm_flush_to_file(&saudio)) != 0)
00343                 return rez;
00344         return 0;
00345 }
00346 
00347 void camogm_audio_ogm_push(void *buf, int len, long granules_shift, int prefix) {
00348         u_int16_t samp_in_subpacket = granules_shift;
00349         unsigned char *h = (unsigned char *)buf - (1 + sizeof(samp_in_subpacket));
00350         int j;
00351         int rez;
00352         
00353         h[0] = 0x00;
00354         h[0] = ((sizeof(samp_in_subpacket) & 3) << 6) + ((sizeof(samp_in_subpacket) & 4) >> 1);
00355         h[0] |= PACKET_IS_SYNCPOINT;
00356         for(j = 0; j < sizeof(samp_in_subpacket); j++) {
00357                 h[j + 1] = (unsigned char)(samp_in_subpacket & 0xFF);
00358                 samp_in_subpacket = samp_in_subpacket >> 8;
00359         }
00360         ogg_packet packet;
00361         packet.bytes = len + 1 + sizeof(samp_in_subpacket);
00362         packet.packet = (char *)h;
00363         packet.b_o_s = 0;
00364         packet.e_o_s = 0;
00365         packet.packetno = saudio.packetno++;;
00366         packet.granulepos = saudio.granulepos;
00367         saudio.granulepos += (ogg_int64_t)granules_shift;
00368         ogg_stream_packetin(&saudio.os, &packet);
00369         rez = ogm_flush_to_file(&saudio);
00370 }

Generated on Thu Aug 7 16:18:59 2008 for elphel by  doxygen 1.5.1