Loading src/camogm.c +64 −93 Original line number Diff line number Diff line Loading @@ -168,6 +168,7 @@ static void camogm_set_dummy_read(camogm_state *state, int d); static void camogm_set_audio_state(camogm_state *state, char *args); static void camogm_set_audio_volume(camogm_state *state, char *args); static void camogm_set_audio_format(camogm_state *state, char *args); static void camogm_select_sync_port(camogm_state *state); void put_uint16(void *buf, u_int16_t val) { Loading Loading @@ -356,7 +357,11 @@ int camogm_start(camogm_state *state, bool restart) int * ifp_this = (int*)&(state->this_frame_params[port]); if (state->kml_enable) camogm_init_kml(); // do nothing audio_init(&state->audio, restart); if (state->frames_skip > 0) { state->audio.audio_enable = 0; D0(fprintf(debug_file, "Audio recording is not supported in time lapse mode, audio disabled\n")); } audio_init_hw(&state->audio, restart); if (state->format != state->set_format) { state->format = state->set_format; switch (state->format) { Loading Loading @@ -501,8 +506,12 @@ int camogm_start(camogm_state *state, bool restart) } } // init audio stuff camogm_select_sync_port(state); state->audio.frame_period_us = state->frame_period[state->audio.sync_port]; audio_init_sw(&state->audio, restart, state->frames_per_chunk); // here we are ready to initialize Ogm (or other) file audio_start(&state->audio); switch (state->format) { case CAMOGM_FORMAT_NONE: rslt = 0; break; case CAMOGM_FORMAT_OGM: rslt = camogm_start_ogm(state); break; Loading Loading @@ -540,12 +549,6 @@ int sendImageFrame(camogm_state *state) int fp; int port = state->port_num; // === debug code === struct timeval tv; gettimeofday(&tv, NULL); fprintf(debug_file, "start time %ld:%06ld\n", tv.tv_sec, tv.tv_usec); // === end of debug === // This is probably needed only for Quicktime (not to exceed already allocated frame index) if (!state->rawdev_op && (state->frameno >= (state->max_frames))) { D3(fprintf(debug_file, "sendImageFrame:1: state->frameno(0x%x) >= state->max_frames(0x%x)\n", state->frameno, state->max_frames)); Loading Loading @@ -630,11 +633,6 @@ int sendImageFrame(camogm_state *state) return -CAMOGM_FRAME_NOT_READY; // the required frame is not ready } // === debug code === gettimeofday(&tv, NULL); fprintf(debug_file, " time %ld:%06ld ", tv.tv_sec, tv.tv_usec); // === end of debug === D3(fprintf(debug_file, "_4_")); if (state->exif) { D3(fprintf(debug_file, "_5_")); Loading Loading @@ -697,10 +695,10 @@ int sendImageFrame(camogm_state *state) state->audio.ts_video.tv_usec = state->this_frame_params[port].timestamp_usec; int sync_ok = 1; // synchronize audio and video before recording has started, this need to be done only once if (state->audio.ctx_a.begin_of_stream_with_audio) { if (state->audio.begin_of_stream_with_audio) { D6(fprintf(debug_file, "\n")); if (state->audio.ctx_a.audio_trigger) { state->audio.ctx_a.audio_trigger = 0; if (state->audio.audio_trigger) { state->audio.audio_trigger = 0; // calculate how many audio frames we need to skip to synch with the next video frame state->audio.ts_video_start = state->audio.ts_audio; struct timeval tv = state->audio.ts_video; // next frame right after audio started Loading @@ -708,18 +706,19 @@ int sendImageFrame(camogm_state *state) tv.tv_usec += state->frame_period[port]; time_normalize(&tv); } struct timeval skip_audio_time = time_sub(&tv, &state->audio.ts_audio); // audio time we need to skip to the next frame struct timeval skip_audio_time; // audio time we need to skip to the next frame timersub(&tv, &state->audio.ts_audio, &skip_audio_time); unsigned long long skip_audio_us = time_to_us(&skip_audio_time); double s = state->audio.audio_rate; s /= 1000.0; s *= skip_audio_us; s /= 1000.0; state->audio.ctx_a.audio_skip_samples = (long) s; state->audio.audio_skip_samples = (long) s; state->audio.ctx_a.time_start = tv; D6(fprintf(debug_file , "audio started at: %ld:%06ld; we need to record it from: %ld:%06ld; audio_to_skip_us == %lld; " "audio samples to skip == %lld\n", D6(fprintf(debug_file , "audio started at: %ld:%06ld; we need to record it from: %ld:%06ld; skip_audio_us == %lld; " "audio samples to skip == %lu\n", state->audio.ts_audio.tv_sec, state->audio.ts_audio.tv_usec, tv.tv_sec, tv.tv_usec, skip_audio_us, state->audio.ctx_a.audio_skip_samples)); state->audio.audio_skip_samples)); } D6(fprintf(debug_file, "audio (start): %ld:%06ld; video (current): %ld:%06ld; frame period is: %d us\n", state->audio.ts_audio.tv_sec, state->audio.ts_audio.tv_usec, state->audio.ts_video.tv_sec, state->audio.ts_video.tv_usec, Loading @@ -729,15 +728,11 @@ int sendImageFrame(camogm_state *state) sync_ok = 0; } else { D6(fprintf(debug_file, "save video frame with time: %ld:%06ld\n", state->audio.ts_video.tv_sec, state->audio.ts_video.tv_usec)); state->audio.ctx_a.begin_of_stream_with_audio = 0; state->audio.begin_of_stream_with_audio = 0; state->chunk_frame_cntr = state->frames_per_chunk; } } // === debug code === gettimeofday(&tv, NULL); fprintf(debug_file, " time %ld:%06ld ", tv.tv_sec, tv.tv_usec); // === end of debug === if (sync_ok) { switch (state->format) { case CAMOGM_FORMAT_NONE: rslt = 0; break; Loading @@ -751,11 +746,6 @@ int sendImageFrame(camogm_state *state) rslt = 0; } // === debug code === gettimeofday(&tv, NULL); fprintf(debug_file, " time %ld:%06ld ", tv.tv_sec, tv.tv_usec); // === end of debug === if (rslt) { D3(fprintf(debug_file, "sendImageFrame:12: camogm_frame_***() returned %d\n", rslt)); return rslt; Loading Loading @@ -1444,14 +1434,7 @@ char * getLineFromPipe(FILE* npipe) if (!cmdbufp) cmdbuf[cmdbufp] = 0; //null-terminate first access (probably not needed for the static buffer nlp = strpbrk(cmdbuf, ";\n"); if (!nlp) { //no complete string, try to read more // === debug code (around fread) === struct timeval tv1, tv2; gettimeofday(&tv1, NULL); fl = fread(&cmdbuf[cmdbufp], 1, sizeof(cmdbuf) - cmdbufp - 1, npipe); gettimeofday(&tv2, NULL); fprintf(debug_file, "pipe read time: start %ld:%06ld, end %ld:%06ld\n", tv1.tv_sec, tv1.tv_usec, tv2.tv_sec, tv2.tv_usec); // === end of debug === cmdbuf[cmdbufp + fl] = 0; // is there any complete string in a buffer after reading? nlp = strpbrk(&cmdbuf[cmdbufp], ";\n"); // there were no new lines before cmdbufp Loading Loading @@ -1761,57 +1744,30 @@ int listener_loop(camogm_state *state) } else if (state->prog_state == STATE_RUNNING) { // no commands in queue, started switch ((rslt = -sendImageFrame(state))) { case 0: { // === debug === double fps = 1000000 / state->frame_period[state->port_num]; double avg_rate = 0; double ratio = 0; struct timeval tv; int samples; if (state->frameno != 0) { avg_rate = ((double)(state->audio.audio_samples + state->audio.avail_samples) / (double)state->frameno) * fps; ratio = (double)state->audio.audio_rate / avg_rate; } samples = ((double)state->frameno / fps) * state->audio.audio_rate; fprintf(debug_file, "frames recorded: %d, average sampling rate: %f, ratio: %f, expected sample count: %d\n", state->frameno, avg_rate, ratio, samples); gettimeofday(&tv, NULL); fprintf(debug_file, "system time %ld:%06ld\n", tv.tv_sec, tv.tv_usec); // === end of debug === // skip audio processing while sync video frame is not found if (state->format == CAMOGM_FORMAT_MOV && !state->audio.ctx_a.begin_of_stream_with_audio) { // skip audio processing while not in sync with video if (state->format == CAMOGM_FORMAT_MOV && state->audio.audio_enable && !state->audio.begin_of_stream_with_audio) { state->chunk_frame_cntr--; if (state->chunk_frame_cntr == 0) { state->audio.save_data = true; state->chunk_frame_cntr = state->frames_per_chunk; } else { D6(fprintf(debug_file, "not recording audio samples after this frame\n")); } audio_process(&state->audio); // === debug code === float fps = 1000000 / state->frame_period[state->port_num]; int samples; samples = ((float)state->frameno / fps) * state->audio.audio_rate; float r = (float)state->audio.audio_samples / (float)samples; fprintf(debug_file, "(recorded samples / expected samples) = %f\n", r); long calc_diff = samples - state->audio.calc_frames; fprintf(debug_file, "calc_frames_diff = %ld\n", calc_diff); // === end of debug === state->audio.frame_period = state->frame_period[state->port_num]; } } break; // frame sent OK, nothing to do (TODO: check file length/duration) case CAMOGM_FRAME_NOT_READY: // just wait for the frame to appear at the current pointer // we'll wait for a frame, not to waste resources. But if the compressor is stopped this program will not respond to any commands // TODO - add another wait with (short) timeout? if (state->audio.audio_enable == 0 || state->audio.sleep_period_us == 0) { fp0 = lseek(state->fd_circ[curr_port], 0, SEEK_CUR); if (fp0 < 0) { D0(fprintf(debug_file, "%s:line %d got broken frame (%d) before waiting for ready\n", __FILE__, __LINE__, fp0)); rslt = CAMOGM_FRAME_BROKEN; } else { // === debug code (around lseek) === struct timeval tv1, tv2; gettimeofday(&tv1, NULL); fp1 = lseek(state->fd_circ[curr_port], LSEEK_CIRC_WAIT, SEEK_END); gettimeofday(&tv2, NULL); fprintf(debug_file,"time in sleep: start %ld:%06ld, end %ld:%06ld\n", tv1.tv_sec, tv1.tv_usec, tv2.tv_sec, tv2.tv_usec); // === end of debug === if (fp1 < 0) { D0(fprintf(debug_file, "%s:line %d got broken frame (%d) while waiting for ready. Before that fp0=0x%x\n", __FILE__, __LINE__, fp1, fp0)); rslt = CAMOGM_FRAME_BROKEN; Loading @@ -1819,6 +1775,13 @@ int listener_loop(camogm_state *state) break; } } } else { // frame period is too long for sleep in lseek, use shorter sleep periods and process audio buffer in between audio_process(&state->audio); D6(fprintf(debug_file, "usleep(%u)\n", state->audio.sleep_period_us)); usleep(state->audio.sleep_period_us); break; } // no break case CAMOGM_FRAME_CHANGED: // frame parameters have changed case CAMOGM_FRAME_NEXTFILE: // next file needed (need to switch to a new file (time/size exceeded limit) Loading Loading @@ -2094,12 +2057,6 @@ unsigned int select_port(camogm_state *state) D6(fprintf(debug_file, "Selecting sensor port, buffer free size: ")); for (int i = 0; i < SENSOR_PORTS; i++) { // === debug code === struct timeval tv; gettimeofday(&tv, NULL); fprintf(debug_file, " time: %ld:%06ld ", tv.tv_sec, tv.tv_usec); // === end of debug === if (is_chn_active(state, i)) { file_pos = lseek(state->fd_circ[i], 0, SEEK_CUR); if (file_pos != -1) { Loading Loading @@ -2403,3 +2360,17 @@ static void get_fpga_time_w(const struct audio *audio, struct timeval *tv) port = state->port_num; *tv = get_fpga_time(state->fd_fparmsall[port], port); } /** * @brief Select sensor port to which audio will be synchronized. * * This function selects the first active sensor port and sets it as synchronization port for * audio stream. Audio data is recorded when new video frame from this port becomes available. * @param[in,out] state a pointer to a structure containing current state */ static void camogm_select_sync_port(camogm_state *state) { for (int i = 0; i < SENSOR_PORTS; i++) if (is_chn_active(state, i)) state->audio.sync_port = i; } src/camogm.h +1 −0 Original line number Diff line number Diff line Loading @@ -223,6 +223,7 @@ typedef struct { int max_frames; int set_max_frames; int frames_per_chunk; ///< QuickTime, the number of samples (images or audio samples) in a chunk unsigned int chunk_frame_cntr; ///< QuickTime, number of video frames recorded in current chunk int set_frames_per_chunk; ///< QuickTime, index for fast forward (sample-to-chunk atom) int frameno; ///< total image frame counter, does not include audio samples unsigned long *frame_lengths; ///< QuickTime; pointer to an array of frame lengths wich includes both image frames Loading src/camogm_audio.c +198 −164 File changed.Preview size limit exceeded, changes collapsed. Show changes src/camogm_audio.h +25 −21 Original line number Diff line number Diff line Loading @@ -25,8 +25,8 @@ #include <sys/time.h> #include <alsa/asoundlib.h> #define SAMPLE_RATE 44100 #define SAMPLE_CHANNELS 2 #define SAMPLE_RATE 44100 ///< default sampling rate #define SAMPLE_CHANNELS 2 ///< default number of audio channels #define SAMPLE_TIME 200 ///< restrict ALSA to have this period, in milliseconds #define BUFFER_TIME 1000 ///< approximate ALSA buffer duration, in milliseconds #define DEFAULT_SND_DEVICE "plughw:0,0" Loading @@ -36,27 +36,34 @@ #define AUDIO_RATE_MAX 44100 #define DEFAULT_AUDIO_VOLUME 0xffff /** * @brief Audio recording context related to stream management. * Members of this structure should not be used outside audio module. */ struct context_audio { char *sbuffer; ///< buffer for audio samples long sbuffer_len; ///< the length of samples buffer in samples long sbuffer_len; ///< total length of audio buffer, in audio frames long sbuffer_pos; ///< pointer to current write position in audio buffer, in frames long read_frames; ///< read granularity, in frames long sample_time; ///< duration of one chunk of audio data, in ms struct timeval time_start; ///< start time, set only when stream starts and updated with each new file struct timeval time_last; ///< calculated time of last audio sample (this value is not taken from ALSA) long rem_samples; ///< remaining samples int begin_of_stream_with_audio; ///< int audio_trigger; ///< indicates the beginning of audio recording to make some initial set ups long long audio_skip_samples; ///< snd_pcm_format_t audio_format; ///< format of audio samples as defined in 'enum snd_pcm_format_t' snd_pcm_t *capture_hnd; ///< ALSA PCM handle }; /** * @brief Various parameters related to audio recording. */ struct audio { int audio_enable; ///< flag indicating that audio is enabled int audio_rate; ///< sample rate, in Hz int audio_channels; ///< number of channels int audio_volume; ///< volume set in range [0..0xFFFF] int sync_port; ///< synch audio stream to this sensor port int set_audio_enable; ///< temporary storage for new value int set_audio_rate; ///< temporary storage for new value Loading @@ -74,27 +81,24 @@ struct audio { struct timeval ts_audio; ///< time stamp when audio stream started struct timeval ts_video; ///< time stamp of each new frame struct timeval ts_video_start; ///< time stamp of starting video frame int frame_period; ///< video frame period, in microseconds snd_pcm_format_t audio_format; ///< format of audio samples as defined in 'enum snd_pcm_format_t' int frame_period_us; ///< video frame period measured for #sync_port, in microseconds unsigned long audio_skip_samples; ///< skip this number audio frames to sync to video int begin_of_stream_with_audio; ///< flag indicating that A/V sync is in progress int audio_trigger; ///< indicates the beginning of audio recording to make some initial set ups bool save_data; ///< flag indicating that audio data should be recorded, otherwise audio frames should be ///< stored in buffer for delayed recording unsigned int sleep_period_us; ///< sleep period between frames while processing audio stream, in microseconds void (*get_fpga_time)(const struct audio *audio, struct timeval *tv);//< callback function which can get FPGA time int (*write_samples)(struct audio *audio, void *buff, long len, long slen); ///< callback function which actually write data to file, this must be set ///< in the camogm_init_* function when appropriate format is selected // === debug === struct timeval sf_timediff; // system to fpga time difference at the beginning of the stream struct timeval m_len; struct timeval sys_fpga_timediff; int avail_samples; long calc_frames; // calculated number of frames by current video frame struct timeval prev_ts_video; long long skip_samples; // === end of debug === }; void audio_init(struct audio *audio, bool restart); void audio_start(struct audio *audio); void audio_init_hw(struct audio *audio, bool restart); void audio_init_sw(struct audio *audio, bool restart, int frames); void audio_process(struct audio *audio); void audio_finish(struct audio *audio, bool reset); void audio_set_volume(int nvolume); unsigned long audio_get_hw_buffer_max(void); #endif /* _CAMOGM_AUDIO_H */ src/camogm_mov.c +4 −17 Original line number Diff line number Diff line Loading @@ -26,11 +26,7 @@ #include <sys/types.h> #include <assert.h> // for debug only #include <math.h> #include "camogm_mov.h" #include "thelper.h" /** @brief QuickTime header length (w/o index tables) enough to accommodate static data */ #define QUICKTIME_MIN_HEADER 0x300 Loading Loading @@ -228,9 +224,9 @@ int camogm_frame_mov(camogm_state *state) /** * Write audio samples to file. * @param[in] buff pointer to buffer containing audio samples * @param[in] buff pointer to buffer containing audio frames * @param[in] len the size of buffer, in bytes * @param[in] slen the number of audio samples in buffer * @param[in] slen the number of audio frames in buffer * @return 0 if data was recorded successfully and negative error code otherwise */ static int camogm_audio_mov(struct audio *audio, void *buff, long len, long slen) Loading @@ -240,7 +236,7 @@ static int camogm_audio_mov(struct audio *audio, void *buff, long len, long slen ssize_t wr_len; camogm_state *state = container_of(audio, camogm_state, audio); D6(fprintf(debug_file, "write audio sample, len = %ld, slen = %ld\n", len, slen)); D6(fprintf(debug_file, "write audio chunk, len = %ld, slen = %ld\n", len, slen)); wr_len = write(state->ivf, buff, len); if (wr_len < len) { Loading Loading @@ -289,19 +285,15 @@ int camogm_end_mov(camogm_state *state) q_template, // string containing header template state->ivf, // output file descriptor (opened) state->width, // width in pixels state->height, state->height, // height in pixels state->frameno, // the number of image frames state->frame_period[port] / (1000000 / timescale), state->frames_per_chunk, 0, // frame size - will look in the table (int)((float)timescale / (state->timescale)), // state->frame_lengths, // array of frame lengths to build an index NULL, // array of frame lengths to build an index state->frame_data_start ); // === debug code === fprintf(debug_file, "total # of video frames: %d, total # of audio samples: %ld\n", state->frameno, state->audio.audio_samples); // === end of debug === close(state->ivf); state->ivf = -1; // free memory used for index Loading Loading @@ -640,11 +632,6 @@ int quicktime_template_parser( camogm_state *state, iFileLen = strlen(iFile); lseek(ofd, 0, SEEK_SET); // === debug === struct timeval m_len = state->audio.m_len; // duration of movie fprintf(debug_file, "frameno: %d, duration: %ld:%06ld, audio_samples: %ld\n", state->frameno, m_len.tv_sec, m_len.tv_usec, state->audio.audio_samples); // === ebd of debug === audio_timescale = state->audio.audio_rate; audio_rate = audio_timescale; // QuickTime defines sample rate as unsigned 16.16 fixed-point number audio_rate <<= 16; Loading Loading
src/camogm.c +64 −93 Original line number Diff line number Diff line Loading @@ -168,6 +168,7 @@ static void camogm_set_dummy_read(camogm_state *state, int d); static void camogm_set_audio_state(camogm_state *state, char *args); static void camogm_set_audio_volume(camogm_state *state, char *args); static void camogm_set_audio_format(camogm_state *state, char *args); static void camogm_select_sync_port(camogm_state *state); void put_uint16(void *buf, u_int16_t val) { Loading Loading @@ -356,7 +357,11 @@ int camogm_start(camogm_state *state, bool restart) int * ifp_this = (int*)&(state->this_frame_params[port]); if (state->kml_enable) camogm_init_kml(); // do nothing audio_init(&state->audio, restart); if (state->frames_skip > 0) { state->audio.audio_enable = 0; D0(fprintf(debug_file, "Audio recording is not supported in time lapse mode, audio disabled\n")); } audio_init_hw(&state->audio, restart); if (state->format != state->set_format) { state->format = state->set_format; switch (state->format) { Loading Loading @@ -501,8 +506,12 @@ int camogm_start(camogm_state *state, bool restart) } } // init audio stuff camogm_select_sync_port(state); state->audio.frame_period_us = state->frame_period[state->audio.sync_port]; audio_init_sw(&state->audio, restart, state->frames_per_chunk); // here we are ready to initialize Ogm (or other) file audio_start(&state->audio); switch (state->format) { case CAMOGM_FORMAT_NONE: rslt = 0; break; case CAMOGM_FORMAT_OGM: rslt = camogm_start_ogm(state); break; Loading Loading @@ -540,12 +549,6 @@ int sendImageFrame(camogm_state *state) int fp; int port = state->port_num; // === debug code === struct timeval tv; gettimeofday(&tv, NULL); fprintf(debug_file, "start time %ld:%06ld\n", tv.tv_sec, tv.tv_usec); // === end of debug === // This is probably needed only for Quicktime (not to exceed already allocated frame index) if (!state->rawdev_op && (state->frameno >= (state->max_frames))) { D3(fprintf(debug_file, "sendImageFrame:1: state->frameno(0x%x) >= state->max_frames(0x%x)\n", state->frameno, state->max_frames)); Loading Loading @@ -630,11 +633,6 @@ int sendImageFrame(camogm_state *state) return -CAMOGM_FRAME_NOT_READY; // the required frame is not ready } // === debug code === gettimeofday(&tv, NULL); fprintf(debug_file, " time %ld:%06ld ", tv.tv_sec, tv.tv_usec); // === end of debug === D3(fprintf(debug_file, "_4_")); if (state->exif) { D3(fprintf(debug_file, "_5_")); Loading Loading @@ -697,10 +695,10 @@ int sendImageFrame(camogm_state *state) state->audio.ts_video.tv_usec = state->this_frame_params[port].timestamp_usec; int sync_ok = 1; // synchronize audio and video before recording has started, this need to be done only once if (state->audio.ctx_a.begin_of_stream_with_audio) { if (state->audio.begin_of_stream_with_audio) { D6(fprintf(debug_file, "\n")); if (state->audio.ctx_a.audio_trigger) { state->audio.ctx_a.audio_trigger = 0; if (state->audio.audio_trigger) { state->audio.audio_trigger = 0; // calculate how many audio frames we need to skip to synch with the next video frame state->audio.ts_video_start = state->audio.ts_audio; struct timeval tv = state->audio.ts_video; // next frame right after audio started Loading @@ -708,18 +706,19 @@ int sendImageFrame(camogm_state *state) tv.tv_usec += state->frame_period[port]; time_normalize(&tv); } struct timeval skip_audio_time = time_sub(&tv, &state->audio.ts_audio); // audio time we need to skip to the next frame struct timeval skip_audio_time; // audio time we need to skip to the next frame timersub(&tv, &state->audio.ts_audio, &skip_audio_time); unsigned long long skip_audio_us = time_to_us(&skip_audio_time); double s = state->audio.audio_rate; s /= 1000.0; s *= skip_audio_us; s /= 1000.0; state->audio.ctx_a.audio_skip_samples = (long) s; state->audio.audio_skip_samples = (long) s; state->audio.ctx_a.time_start = tv; D6(fprintf(debug_file , "audio started at: %ld:%06ld; we need to record it from: %ld:%06ld; audio_to_skip_us == %lld; " "audio samples to skip == %lld\n", D6(fprintf(debug_file , "audio started at: %ld:%06ld; we need to record it from: %ld:%06ld; skip_audio_us == %lld; " "audio samples to skip == %lu\n", state->audio.ts_audio.tv_sec, state->audio.ts_audio.tv_usec, tv.tv_sec, tv.tv_usec, skip_audio_us, state->audio.ctx_a.audio_skip_samples)); state->audio.audio_skip_samples)); } D6(fprintf(debug_file, "audio (start): %ld:%06ld; video (current): %ld:%06ld; frame period is: %d us\n", state->audio.ts_audio.tv_sec, state->audio.ts_audio.tv_usec, state->audio.ts_video.tv_sec, state->audio.ts_video.tv_usec, Loading @@ -729,15 +728,11 @@ int sendImageFrame(camogm_state *state) sync_ok = 0; } else { D6(fprintf(debug_file, "save video frame with time: %ld:%06ld\n", state->audio.ts_video.tv_sec, state->audio.ts_video.tv_usec)); state->audio.ctx_a.begin_of_stream_with_audio = 0; state->audio.begin_of_stream_with_audio = 0; state->chunk_frame_cntr = state->frames_per_chunk; } } // === debug code === gettimeofday(&tv, NULL); fprintf(debug_file, " time %ld:%06ld ", tv.tv_sec, tv.tv_usec); // === end of debug === if (sync_ok) { switch (state->format) { case CAMOGM_FORMAT_NONE: rslt = 0; break; Loading @@ -751,11 +746,6 @@ int sendImageFrame(camogm_state *state) rslt = 0; } // === debug code === gettimeofday(&tv, NULL); fprintf(debug_file, " time %ld:%06ld ", tv.tv_sec, tv.tv_usec); // === end of debug === if (rslt) { D3(fprintf(debug_file, "sendImageFrame:12: camogm_frame_***() returned %d\n", rslt)); return rslt; Loading Loading @@ -1444,14 +1434,7 @@ char * getLineFromPipe(FILE* npipe) if (!cmdbufp) cmdbuf[cmdbufp] = 0; //null-terminate first access (probably not needed for the static buffer nlp = strpbrk(cmdbuf, ";\n"); if (!nlp) { //no complete string, try to read more // === debug code (around fread) === struct timeval tv1, tv2; gettimeofday(&tv1, NULL); fl = fread(&cmdbuf[cmdbufp], 1, sizeof(cmdbuf) - cmdbufp - 1, npipe); gettimeofday(&tv2, NULL); fprintf(debug_file, "pipe read time: start %ld:%06ld, end %ld:%06ld\n", tv1.tv_sec, tv1.tv_usec, tv2.tv_sec, tv2.tv_usec); // === end of debug === cmdbuf[cmdbufp + fl] = 0; // is there any complete string in a buffer after reading? nlp = strpbrk(&cmdbuf[cmdbufp], ";\n"); // there were no new lines before cmdbufp Loading Loading @@ -1761,57 +1744,30 @@ int listener_loop(camogm_state *state) } else if (state->prog_state == STATE_RUNNING) { // no commands in queue, started switch ((rslt = -sendImageFrame(state))) { case 0: { // === debug === double fps = 1000000 / state->frame_period[state->port_num]; double avg_rate = 0; double ratio = 0; struct timeval tv; int samples; if (state->frameno != 0) { avg_rate = ((double)(state->audio.audio_samples + state->audio.avail_samples) / (double)state->frameno) * fps; ratio = (double)state->audio.audio_rate / avg_rate; } samples = ((double)state->frameno / fps) * state->audio.audio_rate; fprintf(debug_file, "frames recorded: %d, average sampling rate: %f, ratio: %f, expected sample count: %d\n", state->frameno, avg_rate, ratio, samples); gettimeofday(&tv, NULL); fprintf(debug_file, "system time %ld:%06ld\n", tv.tv_sec, tv.tv_usec); // === end of debug === // skip audio processing while sync video frame is not found if (state->format == CAMOGM_FORMAT_MOV && !state->audio.ctx_a.begin_of_stream_with_audio) { // skip audio processing while not in sync with video if (state->format == CAMOGM_FORMAT_MOV && state->audio.audio_enable && !state->audio.begin_of_stream_with_audio) { state->chunk_frame_cntr--; if (state->chunk_frame_cntr == 0) { state->audio.save_data = true; state->chunk_frame_cntr = state->frames_per_chunk; } else { D6(fprintf(debug_file, "not recording audio samples after this frame\n")); } audio_process(&state->audio); // === debug code === float fps = 1000000 / state->frame_period[state->port_num]; int samples; samples = ((float)state->frameno / fps) * state->audio.audio_rate; float r = (float)state->audio.audio_samples / (float)samples; fprintf(debug_file, "(recorded samples / expected samples) = %f\n", r); long calc_diff = samples - state->audio.calc_frames; fprintf(debug_file, "calc_frames_diff = %ld\n", calc_diff); // === end of debug === state->audio.frame_period = state->frame_period[state->port_num]; } } break; // frame sent OK, nothing to do (TODO: check file length/duration) case CAMOGM_FRAME_NOT_READY: // just wait for the frame to appear at the current pointer // we'll wait for a frame, not to waste resources. But if the compressor is stopped this program will not respond to any commands // TODO - add another wait with (short) timeout? if (state->audio.audio_enable == 0 || state->audio.sleep_period_us == 0) { fp0 = lseek(state->fd_circ[curr_port], 0, SEEK_CUR); if (fp0 < 0) { D0(fprintf(debug_file, "%s:line %d got broken frame (%d) before waiting for ready\n", __FILE__, __LINE__, fp0)); rslt = CAMOGM_FRAME_BROKEN; } else { // === debug code (around lseek) === struct timeval tv1, tv2; gettimeofday(&tv1, NULL); fp1 = lseek(state->fd_circ[curr_port], LSEEK_CIRC_WAIT, SEEK_END); gettimeofday(&tv2, NULL); fprintf(debug_file,"time in sleep: start %ld:%06ld, end %ld:%06ld\n", tv1.tv_sec, tv1.tv_usec, tv2.tv_sec, tv2.tv_usec); // === end of debug === if (fp1 < 0) { D0(fprintf(debug_file, "%s:line %d got broken frame (%d) while waiting for ready. Before that fp0=0x%x\n", __FILE__, __LINE__, fp1, fp0)); rslt = CAMOGM_FRAME_BROKEN; Loading @@ -1819,6 +1775,13 @@ int listener_loop(camogm_state *state) break; } } } else { // frame period is too long for sleep in lseek, use shorter sleep periods and process audio buffer in between audio_process(&state->audio); D6(fprintf(debug_file, "usleep(%u)\n", state->audio.sleep_period_us)); usleep(state->audio.sleep_period_us); break; } // no break case CAMOGM_FRAME_CHANGED: // frame parameters have changed case CAMOGM_FRAME_NEXTFILE: // next file needed (need to switch to a new file (time/size exceeded limit) Loading Loading @@ -2094,12 +2057,6 @@ unsigned int select_port(camogm_state *state) D6(fprintf(debug_file, "Selecting sensor port, buffer free size: ")); for (int i = 0; i < SENSOR_PORTS; i++) { // === debug code === struct timeval tv; gettimeofday(&tv, NULL); fprintf(debug_file, " time: %ld:%06ld ", tv.tv_sec, tv.tv_usec); // === end of debug === if (is_chn_active(state, i)) { file_pos = lseek(state->fd_circ[i], 0, SEEK_CUR); if (file_pos != -1) { Loading Loading @@ -2403,3 +2360,17 @@ static void get_fpga_time_w(const struct audio *audio, struct timeval *tv) port = state->port_num; *tv = get_fpga_time(state->fd_fparmsall[port], port); } /** * @brief Select sensor port to which audio will be synchronized. * * This function selects the first active sensor port and sets it as synchronization port for * audio stream. Audio data is recorded when new video frame from this port becomes available. * @param[in,out] state a pointer to a structure containing current state */ static void camogm_select_sync_port(camogm_state *state) { for (int i = 0; i < SENSOR_PORTS; i++) if (is_chn_active(state, i)) state->audio.sync_port = i; }
src/camogm.h +1 −0 Original line number Diff line number Diff line Loading @@ -223,6 +223,7 @@ typedef struct { int max_frames; int set_max_frames; int frames_per_chunk; ///< QuickTime, the number of samples (images or audio samples) in a chunk unsigned int chunk_frame_cntr; ///< QuickTime, number of video frames recorded in current chunk int set_frames_per_chunk; ///< QuickTime, index for fast forward (sample-to-chunk atom) int frameno; ///< total image frame counter, does not include audio samples unsigned long *frame_lengths; ///< QuickTime; pointer to an array of frame lengths wich includes both image frames Loading
src/camogm_audio.c +198 −164 File changed.Preview size limit exceeded, changes collapsed. Show changes
src/camogm_audio.h +25 −21 Original line number Diff line number Diff line Loading @@ -25,8 +25,8 @@ #include <sys/time.h> #include <alsa/asoundlib.h> #define SAMPLE_RATE 44100 #define SAMPLE_CHANNELS 2 #define SAMPLE_RATE 44100 ///< default sampling rate #define SAMPLE_CHANNELS 2 ///< default number of audio channels #define SAMPLE_TIME 200 ///< restrict ALSA to have this period, in milliseconds #define BUFFER_TIME 1000 ///< approximate ALSA buffer duration, in milliseconds #define DEFAULT_SND_DEVICE "plughw:0,0" Loading @@ -36,27 +36,34 @@ #define AUDIO_RATE_MAX 44100 #define DEFAULT_AUDIO_VOLUME 0xffff /** * @brief Audio recording context related to stream management. * Members of this structure should not be used outside audio module. */ struct context_audio { char *sbuffer; ///< buffer for audio samples long sbuffer_len; ///< the length of samples buffer in samples long sbuffer_len; ///< total length of audio buffer, in audio frames long sbuffer_pos; ///< pointer to current write position in audio buffer, in frames long read_frames; ///< read granularity, in frames long sample_time; ///< duration of one chunk of audio data, in ms struct timeval time_start; ///< start time, set only when stream starts and updated with each new file struct timeval time_last; ///< calculated time of last audio sample (this value is not taken from ALSA) long rem_samples; ///< remaining samples int begin_of_stream_with_audio; ///< int audio_trigger; ///< indicates the beginning of audio recording to make some initial set ups long long audio_skip_samples; ///< snd_pcm_format_t audio_format; ///< format of audio samples as defined in 'enum snd_pcm_format_t' snd_pcm_t *capture_hnd; ///< ALSA PCM handle }; /** * @brief Various parameters related to audio recording. */ struct audio { int audio_enable; ///< flag indicating that audio is enabled int audio_rate; ///< sample rate, in Hz int audio_channels; ///< number of channels int audio_volume; ///< volume set in range [0..0xFFFF] int sync_port; ///< synch audio stream to this sensor port int set_audio_enable; ///< temporary storage for new value int set_audio_rate; ///< temporary storage for new value Loading @@ -74,27 +81,24 @@ struct audio { struct timeval ts_audio; ///< time stamp when audio stream started struct timeval ts_video; ///< time stamp of each new frame struct timeval ts_video_start; ///< time stamp of starting video frame int frame_period; ///< video frame period, in microseconds snd_pcm_format_t audio_format; ///< format of audio samples as defined in 'enum snd_pcm_format_t' int frame_period_us; ///< video frame period measured for #sync_port, in microseconds unsigned long audio_skip_samples; ///< skip this number audio frames to sync to video int begin_of_stream_with_audio; ///< flag indicating that A/V sync is in progress int audio_trigger; ///< indicates the beginning of audio recording to make some initial set ups bool save_data; ///< flag indicating that audio data should be recorded, otherwise audio frames should be ///< stored in buffer for delayed recording unsigned int sleep_period_us; ///< sleep period between frames while processing audio stream, in microseconds void (*get_fpga_time)(const struct audio *audio, struct timeval *tv);//< callback function which can get FPGA time int (*write_samples)(struct audio *audio, void *buff, long len, long slen); ///< callback function which actually write data to file, this must be set ///< in the camogm_init_* function when appropriate format is selected // === debug === struct timeval sf_timediff; // system to fpga time difference at the beginning of the stream struct timeval m_len; struct timeval sys_fpga_timediff; int avail_samples; long calc_frames; // calculated number of frames by current video frame struct timeval prev_ts_video; long long skip_samples; // === end of debug === }; void audio_init(struct audio *audio, bool restart); void audio_start(struct audio *audio); void audio_init_hw(struct audio *audio, bool restart); void audio_init_sw(struct audio *audio, bool restart, int frames); void audio_process(struct audio *audio); void audio_finish(struct audio *audio, bool reset); void audio_set_volume(int nvolume); unsigned long audio_get_hw_buffer_max(void); #endif /* _CAMOGM_AUDIO_H */
src/camogm_mov.c +4 −17 Original line number Diff line number Diff line Loading @@ -26,11 +26,7 @@ #include <sys/types.h> #include <assert.h> // for debug only #include <math.h> #include "camogm_mov.h" #include "thelper.h" /** @brief QuickTime header length (w/o index tables) enough to accommodate static data */ #define QUICKTIME_MIN_HEADER 0x300 Loading Loading @@ -228,9 +224,9 @@ int camogm_frame_mov(camogm_state *state) /** * Write audio samples to file. * @param[in] buff pointer to buffer containing audio samples * @param[in] buff pointer to buffer containing audio frames * @param[in] len the size of buffer, in bytes * @param[in] slen the number of audio samples in buffer * @param[in] slen the number of audio frames in buffer * @return 0 if data was recorded successfully and negative error code otherwise */ static int camogm_audio_mov(struct audio *audio, void *buff, long len, long slen) Loading @@ -240,7 +236,7 @@ static int camogm_audio_mov(struct audio *audio, void *buff, long len, long slen ssize_t wr_len; camogm_state *state = container_of(audio, camogm_state, audio); D6(fprintf(debug_file, "write audio sample, len = %ld, slen = %ld\n", len, slen)); D6(fprintf(debug_file, "write audio chunk, len = %ld, slen = %ld\n", len, slen)); wr_len = write(state->ivf, buff, len); if (wr_len < len) { Loading Loading @@ -289,19 +285,15 @@ int camogm_end_mov(camogm_state *state) q_template, // string containing header template state->ivf, // output file descriptor (opened) state->width, // width in pixels state->height, state->height, // height in pixels state->frameno, // the number of image frames state->frame_period[port] / (1000000 / timescale), state->frames_per_chunk, 0, // frame size - will look in the table (int)((float)timescale / (state->timescale)), // state->frame_lengths, // array of frame lengths to build an index NULL, // array of frame lengths to build an index state->frame_data_start ); // === debug code === fprintf(debug_file, "total # of video frames: %d, total # of audio samples: %ld\n", state->frameno, state->audio.audio_samples); // === end of debug === close(state->ivf); state->ivf = -1; // free memory used for index Loading Loading @@ -640,11 +632,6 @@ int quicktime_template_parser( camogm_state *state, iFileLen = strlen(iFile); lseek(ofd, 0, SEEK_SET); // === debug === struct timeval m_len = state->audio.m_len; // duration of movie fprintf(debug_file, "frameno: %d, duration: %ld:%06ld, audio_samples: %ld\n", state->frameno, m_len.tv_sec, m_len.tv_usec, state->audio.audio_samples); // === ebd of debug === audio_timescale = state->audio.audio_rate; audio_rate = audio_timescale; // QuickTime defines sample rate as unsigned 16.16 fixed-point number audio_rate <<= 16; Loading