int frameIsLastFrame (uint8_t *data) { int retVal = 0; if (PAVE_CHECK (data)) { parrot_video_encapsulation_t *PaVE = (parrot_video_encapsulation_t *)data; if (PAVE_CTRL_LAST_FRAME_IN_STREAM & PaVE->control) { retVal = 1; } } return retVal; }
C_RESULT video_stage_merge_slices_transform(video_stage_merge_slices_config_t *cfg, vp_api_io_data_t *in, vp_api_io_data_t *out) { bool_t switchBuffers; bool_t dataReady = 0; video_stage_merge_slices_buffer_t *buf; int dataSize; parrot_video_encapsulation_t *PaVE; parrot_video_encapsulation_t *mergingPaVE; out->size = 0; if(out->status == VP_API_STATUS_INIT) { /* By default, feed the next stage with our local output */ out->numBuffers = 1; out->buffers = cfg->bufs[0].bufferPointer; out->buffers[0] = cfg->bufs[0].buffer; out->indexBuffer = 0; out->lineSize = 0; out->status = VP_API_STATUS_PROCESSING; } // check input PaVE = (parrot_video_encapsulation_t *) in->buffers[in->indexBuffer]; mergingPaVE = (parrot_video_encapsulation_t *) cfg->bufs[cfg->mergingBuffer].buffer; VIDEO_SLICE_DEBUG("PAVE frm %d sl %d/%d %s\n ", PaVE->frame_number, PaVE->slice_index+1, PaVE->total_slices, (PaVE->frame_type == FRAME_TYPE_I_FRAME || PaVE->frame_type == FRAME_TYPE_IDR_FRAME) ? "I-frm":"p-frm" ); if ( (PaVE==NULL) || (!PAVE_CHECK(PaVE)) || (PaVE->total_slices == 1) ) { // No slices, just send the data to the next stage /* Feed the next stage with the previous stage's output */ out->buffers = in->buffers; out->indexBuffer = in->indexBuffer; out->lineSize = in->lineSize; out->numBuffers = in->numBuffers; out->status = in->status; out->size = in->size; out->status = VP_API_STATUS_PROCESSING; /* Get rid of previously accumulated data */ video_stage_merge_slices_reset(cfg); /* IPHONE DEBUG : set slices miss to 0/1 (to avoid keeping old/fake slice datas) */ DEBUG_totalSlices = 1; DEBUG_nbSlices = 0; return C_OK; } /* * Check if the incoming PaVE belongs to the same frame. */ switchBuffers = (mergingPaVE) /* At program startup this buffer is empty and switching makes no sense */ && ( !(pave_is_same_frame(PaVE,mergingPaVE)) ); /* If not the same frame, start building a new one */ if (switchBuffers) { if (0 != DEBUG_prevNumber) { int DEBUG_tempMiss = (PaVE->frame_number - (DEBUG_prevNumber + 1)); if (0 < DEBUG_tempMiss) { DEBUG_missed += DEBUG_tempMiss; } } DEBUG_prevNumber = PaVE->frame_number; cfg->readyBuffer = cfg->mergingBuffer; cfg->mergingBuffer = (cfg->mergingBuffer+1)%2; cfg->bufs[cfg->mergingBuffer].accumulated_size = 0; cfg->bufs[cfg->mergingBuffer].nb_slices = 0; } /* Get a pointer to the buffer to store data to */ buf = &cfg->bufs[cfg->mergingBuffer]; // Check destination buffer size if (buf->buffer_size < (buf->accumulated_size + in->size)) { buf->buffer_size = buf->accumulated_size + in->size; buf->buffer = vp_os_realloc(buf->buffer, buf->buffer_size ); if(!buf->buffer) { return C_FAIL; } } /* Copy data */ if (PaVE->slice_index == 0 || buf->accumulated_size==0) { /* Copy the entire packet */ if (buf->buffer) { vp_os_memcpy(buf->buffer, PaVE, in->size); } buf->accumulated_size = in->size; buf->nb_slices++; } else { #define mymin(x,y) ( ((x)<(y))?(x):(y) ) /* Copy only the payload */ dataSize = mymin(PaVE->payload_size,in->size); /* safety if the PaVE is corrupted */ if (buf->buffer) { vp_os_memcpy(buf->buffer + buf->accumulated_size, in->buffers[in->indexBuffer] + PaVE->header_size, dataSize); } buf->accumulated_size += dataSize; buf->nb_slices++; } /* Select the buffer to send to the next stage */ if (PaVE->slice_index == PaVE->total_slices - 1) { /* The buffer we just used for merging is ready to be sent */ cfg->readyBuffer = cfg->mergingBuffer; cfg->mergingBuffer = (cfg->mergingBuffer+1)%2; cfg->bufs[cfg->mergingBuffer].accumulated_size = 0; cfg->bufs[cfg->mergingBuffer].nb_slices = 0; dataReady = 1; } else if (switchBuffers) { /* Send the previous buffer if it contains something */ dataReady = 1; } // If slice was the last one, continue to next stage if (dataReady) { buf = &cfg->bufs[cfg->readyBuffer]; if (buf->buffer && buf->accumulated_size) { int totalSlices; parrot_video_encapsulation_t *newPaVE = (parrot_video_encapsulation_t *) buf->buffer; /* Save the old value of total slices */ totalSlices = newPaVE->total_slices; newPaVE->payload_size = buf->accumulated_size - PaVE->header_size; newPaVE->slice_index = 0; newPaVE->total_slices = 1; /* Feed the next stage with our local output */ out->size = buf->accumulated_size; out->buffers = buf->bufferPointer; out->buffers[0] = buf->buffer; out->indexBuffer = 0; out->numBuffers = 1; out->lineSize = 0; out->status = VP_API_STATUS_PROCESSING; if(!PAVE_CHECK(buf->buffer)) { printf("%s:%d - No PaVE !\n",__FUNCTION__,__LINE__); assert(0==1); } if (buf->nb_slices != totalSlices) { printf("Missing slices (%d)\n",totalSlices-buf->nb_slices); } DEBUG_nbSlices = 0.9*DEBUG_nbSlices + 0.1*(totalSlices-buf->nb_slices); DEBUG_totalSlices = 0.9*DEBUG_totalSlices + 0.1*totalSlices; } } else { out->size = 0; } if (out->size) { PaVE = (parrot_video_encapsulation_t*) out->buffers[0]; VIDEO_SLICE_DEBUG("Switch %d - Sending - PAVE frm %d sl %d/%d\n ", switchBuffers, PaVE->frame_number, PaVE->slice_index+1, PaVE->total_slices );} return C_OK; }
C_RESULT video_stage_encoded_recorder_transform(video_stage_encoded_recorder_config_t *cfg, vp_api_io_data_t *in, vp_api_io_data_t *out) { vp_os_mutex_lock (&out->lock); vp_os_mutex_lock (&cfg->videoMutex); // Copy in to out if (NULL != in && NULL != out) { out->numBuffers = in->numBuffers; out->indexBuffer = in->indexBuffer; out->lineSize = in->lineSize; out->size = in->size; out->status = in->status; out->buffers = in->buffers; out->status = VP_API_STATUS_PROCESSING; } uint8_t *slice = in->buffers[in->indexBuffer]; parrot_video_encapsulation_t *PaVE = (parrot_video_encapsulation_t *)slice; if (cfg->lastStreamId == PaVE->stream_id) { VER_PRINT ("Got a video slice from an old stream, skipping\n"); vp_os_mutex_unlock (&cfg->videoMutex); vp_os_mutex_unlock (&out->lock); return C_OK; } if(cfg->startRec == VIDEO_ENCODED_START_RECORD) { ardrone_video_error_t vError = ARDRONE_VIDEO_NO_ERROR; cfg->video = ardrone_video_start (cfg->video_filename, cfg->fps, VIDEO_FORMAT, &vError); if (ARDRONE_VIDEO_SUCCEEDED (vError) && NULL != cfg->video) { cfg->startRec=VIDEO_ENCODED_RECORDING; cfg->currentStreamId = PaVE->stream_id; } else { VER_PRINT ("An error occured when creating video"); cfg->startRec=VIDEO_ENCODED_STOPPED; } } if((cfg->startRec == VIDEO_ENCODED_RECORDING) || (cfg->startRec == VIDEO_ENCODED_WAITING_STREAM_END)) { #if USE_LINUX /* Quick and dirty debugging inside AR.Drone Navigation */ if (PAVE_CHECK(slice)) { parrot_video_encapsulation_t * pave = (parrot_video_encapsulation_t*) slice; printf("Recording frame %dx%d num %d \n\033[1A",pave->display_width,pave->display_height,pave->frame_number); if (pave->control & PAVE_CTRL_LAST_FRAME_IN_STREAM) { printf("\n\nEnd of stream PaVE received !\n\n"); } } #endif ardrone_video_error_t vError = ardrone_video_addSlice (cfg->video, slice); if (ARDRONE_VIDEO_FAILED (vError)) { char errBuf [50] = {0}; ardrone_video_error_string (vError, errBuf, 50); VER_PRINT ("Error while recording frame : %s", errBuf); ardrone_video_cleanup (&(cfg->video)); cfg->startRec = VIDEO_ENCODED_STOPPED; } if (1 == frameIsLastFrame (slice)) { VER_PRINT ("Received last frame for current stream, finishing video\n"); video_stage_encoded_recorder_finish (cfg); } } vp_os_mutex_unlock (&cfg->videoMutex); vp_os_mutex_unlock (&out->lock); return C_OK; }