bool CCameraOutput::BeginReadFrame(const void* &out_buffer, int& out_buffer_size) { //printf("Attempting to read camera output\n"); //try and get buffer if(MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(OutputQueue)) { //printf("Reading buffer of %d bytes from output\n",buffer->length); //lock it mmal_buffer_header_mem_lock(buffer); //store it LockedBuffer = buffer; //fill out the output variables and return success out_buffer = buffer->data; out_buffer_size = buffer->length; return true; } //no buffer - return false return false; }
/** Send a buffer header to a port */ static MMAL_STATUS_T splitter_send_output(MMAL_BUFFER_HEADER_T *buffer, MMAL_PORT_T *out_port) { MMAL_BUFFER_HEADER_T *out; MMAL_STATUS_T status; /* Get a buffer header from output port */ out = mmal_queue_get(out_port->priv->module->queue); if (!out) return MMAL_EAGAIN; /* Copy our input buffer header */ status = mmal_buffer_header_replicate(out, buffer); if (status != MMAL_SUCCESS) goto error; /* Send buffer back */ mmal_port_buffer_header_callback(out_port, out); return MMAL_SUCCESS; error: mmal_queue_put_back(out_port->priv->module->queue, out); return status; }
static void jpegencoder2_buffer_callback (MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) { int bytes_written = buffer->length; if(buffer->length) { mmal_buffer_header_mem_lock(buffer); bytes_written = fwrite(buffer->data, 1, buffer->length, jpegoutput2_file); mmal_buffer_header_mem_unlock(buffer); } if(bytes_written != buffer->length) error("Could not write all bytes"); if(buffer->flags & MMAL_BUFFER_HEADER_FLAG_FRAME_END) { fclose(jpegoutput2_file); if(status_filename != 0) { if(!timelapse) { status_file = fopen(status_filename, "w"); fprintf(status_file, "ready"); fclose(status_file); } } image2_cnt++; capturing = 0; } mmal_buffer_header_release(buffer); if (port->is_enabled) { MMAL_STATUS_T status = MMAL_SUCCESS; MMAL_BUFFER_HEADER_T *new_buffer; new_buffer = mmal_queue_get(pool_jpegencoder2->queue); if (new_buffer) status = mmal_port_send_buffer(port, new_buffer); if (!new_buffer || status != MMAL_SUCCESS) error("Could not send buffers to port"); } }
static void h264encoder_buffer_callback (MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) { int bytes_written = buffer->length; if(buffer->length) { mmal_buffer_header_mem_lock(buffer); bytes_written = fwrite(buffer->data, 1, buffer->length, h264output_file); mmal_buffer_header_mem_unlock(buffer); if(bytes_written != buffer->length) error("Could not write all bytes"); } mmal_buffer_header_release(buffer); if (port->is_enabled) { MMAL_STATUS_T status = MMAL_SUCCESS; MMAL_BUFFER_HEADER_T *new_buffer; new_buffer = mmal_queue_get(pool_h264encoder->queue); if (new_buffer) status = mmal_port_send_buffer(port, new_buffer); if (!new_buffer || status != MMAL_SUCCESS) error("Could not send buffers to port"); } }
static void Close(filter_t *filter) { filter_sys_t *sys = filter->p_sys; MMAL_BUFFER_HEADER_T *buffer; if (!sys) return; if (sys->component && sys->component->control->is_enabled) mmal_port_disable(sys->component->control); if (sys->input && sys->input->is_enabled) mmal_port_disable(sys->input); if (sys->output && sys->output->is_enabled) mmal_port_disable(sys->output); if (sys->component && sys->component->is_enabled) mmal_component_disable(sys->component); while ((buffer = mmal_queue_get(sys->filtered_pictures))) { picture_t *pic = (picture_t *)buffer->user_data; picture_Release(pic); } if (sys->filtered_pictures) mmal_queue_destroy(sys->filtered_pictures); if (sys->component) mmal_component_release(sys->component); vlc_sem_destroy(&sys->sem); free(sys); bcm_host_deinit(); }
/** * buffer header callback function for camera output port * * Callback will dump buffer data to the specific file * * @param port Pointer to port from which callback originated * @param buffer mmal buffer header pointer */ static void camera_buffer_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) { int complete = 0; // We pass our file handle and other stuff in via the userdata field. PORT_USERDATA *pData = (PORT_USERDATA *)port->userdata; if (pData) { int bytes_written = buffer->length; if (buffer->length && pData->file_handle) { mmal_buffer_header_mem_lock(buffer); bytes_written = fwrite(buffer->data, 1, buffer->length, pData->file_handle); mmal_buffer_header_mem_unlock(buffer); } // We need to check we wrote what we wanted - it's possible we have run out of storage. if (bytes_written != buffer->length) { vcos_log_error("Unable to write buffer to file - aborting"); complete = 1; } // Check end of frame or error if (buffer->flags & (MMAL_BUFFER_HEADER_FLAG_FRAME_END | MMAL_BUFFER_HEADER_FLAG_TRANSMISSION_FAILED)) complete = 1; } else { vcos_log_error("Received a camera still buffer callback with no state"); } // release buffer back to the pool mmal_buffer_header_release(buffer); // and send one back to the port (if still open) if (port->is_enabled) { MMAL_STATUS_T status; MMAL_BUFFER_HEADER_T *new_buffer = mmal_queue_get(pData->pstate->camera_pool->queue); // and back to the port from there. if (new_buffer) { status = mmal_port_send_buffer(port, new_buffer); } if (!new_buffer || status != MMAL_SUCCESS) vcos_log_error("Unable to return the buffer to the camera still port"); } if (complete) { vcos_semaphore_post(&(pData->complete_semaphore)); } }
static void EncoderBufferCallback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) { //std::cout << "EncoderBufferCallback: " << pthread_self() << std::endl; MmalVideoCallbackData *pData = (MmalVideoCallbackData *)port->userdata; bool mappedBuffer = false; if (pData) { if (buffer->length) { // Copy the image data pData->cs.enter("EncoderBufferCallback"); try { if (pData->acquire) { MmalImageStoreItem * item = pData->imageStore.reserve(buffer); if (item == NULL) { throw Exception("No images available in the MmalImageStore"); } pData->image = &item->image; pData->acquire = false; mappedBuffer = true; } } catch (Exception& e) { std::cerr << "!! Exception thrown in EncoderBufferCallback: " << e << std::endl; } catch (...) { std::cerr << "!! Exception thrown in EncoderBufferCallback" << std::endl; } pData->cs.leave(); } } else { std::cerr << "!! Received a encoder buffer callback with no state" << std::endl; } // release buffer back to the pool if (mappedBuffer) { vcos_semaphore_post(&(pData->complete_semaphore)); } else { mmal_buffer_header_release(buffer); } // and send one back to the port (if still open) if (port->is_enabled) { MMAL_BUFFER_HEADER_T *new_buffer = mmal_queue_get(pData->pool->queue); if (new_buffer) { mmal_port_send_buffer(port, new_buffer); } } }
RaspiCamCvCapture * raspiCamCvCreateCameraCapture(int index) { RaspiCamCvCapture * capture = (RaspiCamCvCapture*)malloc(sizeof(RaspiCamCvCapture)); // Our main data storage vessel.. RASPIVID_STATE * state = (RASPIVID_STATE*)malloc(sizeof(RASPIVID_STATE)); capture->pState = state; MMAL_STATUS_T status = -1; MMAL_PORT_T *camera_video_port = NULL; MMAL_PORT_T *camera_still_port = NULL; bcm_host_init(); // read default status default_status(state); int w = state->width; int h = state->height; state->py = cvCreateImage(cvSize(w,h), IPL_DEPTH_8U, 1); // Y component of YUV I420 frame if (state->graymode==0) { state->pu = cvCreateImage(cvSize(w/2,h/2), IPL_DEPTH_8U, 1); // U component of YUV I420 frame state->pv = cvCreateImage(cvSize(w/2,h/2), IPL_DEPTH_8U, 1); // V component of YUV I420 frame } vcos_semaphore_create(&state->capture_sem, "Capture-Sem", 0); vcos_semaphore_create(&state->capture_done_sem, "Capture-Done-Sem", 0); if (state->graymode==0) { state->pu_big = cvCreateImage(cvSize(w,h), IPL_DEPTH_8U, 1); state->pv_big = cvCreateImage(cvSize(w,h), IPL_DEPTH_8U, 1); state->yuvImage = cvCreateImage(cvSize(w,h), IPL_DEPTH_8U, 3); state->dstImage = cvCreateImage(cvSize(w,h), IPL_DEPTH_8U, 3); // final picture to display } // create camera if (!create_camera_component(state)) { vcos_log_error("%s: Failed to create camera component", __func__); raspiCamCvReleaseCapture(&capture); return NULL; } camera_video_port = state->camera_component->output[MMAL_CAMERA_VIDEO_PORT]; camera_still_port = state->camera_component->output[MMAL_CAMERA_CAPTURE_PORT]; // assign data to use for callback camera_video_port->userdata = (struct MMAL_PORT_USERDATA_T *)state; // start capture if (mmal_port_parameter_set_boolean(camera_video_port, MMAL_PARAMETER_CAPTURE, 1) != MMAL_SUCCESS) { vcos_log_error("%s: Failed to start capture", __func__); raspiCamCvReleaseCapture(&capture); return NULL; } // Send all the buffers to the video port int num = mmal_queue_length(state->video_pool->queue); int q; for (q = 0; q < num; q++) { MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(state->video_pool->queue); if (!buffer) vcos_log_error("Unable to get a required buffer %d from pool queue", q); if (mmal_port_send_buffer(camera_video_port, buffer)!= MMAL_SUCCESS) vcos_log_error("Unable to send a buffer to encoder output port (%d)", q); } //mmal_status_to_int(status); // Disable all our ports that are not handled by connections //check_disable_port(camera_still_port); //if (status != 0) // raspicamcontrol_check_configuration(128); vcos_semaphore_wait(&state->capture_done_sem); return capture; }
/** * main */ int main(int argc, const char **argv) { // Our main data storage vessel.. RASPIVID_STATE state; MMAL_STATUS_T status = MMAL_SUCCESS; MMAL_PORT_T *camera_preview_port = NULL; MMAL_PORT_T *camera_video_port = NULL; MMAL_PORT_T *camera_still_port = NULL; MMAL_PORT_T *preview_input_port = NULL; MMAL_PORT_T *encoder_input_port = NULL; MMAL_PORT_T *encoder_output_port = NULL; FILE *output_file = NULL; bcm_host_init(); // Register our application with the logging system vcos_log_register("RaspiVid", VCOS_LOG_CATEGORY); signal(SIGINT, signal_handler); default_status(&state); // Do we have any parameters if (argc == 1) { fprintf(stderr, "\n%s Camera App %s\n\n", basename(argv[0]), VERSION_STRING); display_valid_parameters(basename(argv[0])); exit(0); } // Parse the command line and put options in to our status structure if (parse_cmdline(argc, argv, &state)) { status = -1; exit(0); } if (state.verbose) { fprintf(stderr, "\n%s Camera App %s\n\n", basename(argv[0]), VERSION_STRING); dump_status(&state); } // OK, we have a nice set of parameters. Now set up our components // We have three components. Camera, Preview and encoder. if ((status = create_camera_component(&state)) != MMAL_SUCCESS) { vcos_log_error("%s: Failed to create camera component", __func__); } else if ((status = raspipreview_create(&state.preview_parameters)) != MMAL_SUCCESS) { vcos_log_error("%s: Failed to create preview component", __func__); destroy_camera_component(&state); } else if ((status = create_encoder_component(&state)) != MMAL_SUCCESS) { vcos_log_error("%s: Failed to create encode component", __func__); raspipreview_destroy(&state.preview_parameters); destroy_camera_component(&state); } else { PORT_USERDATA callback_data; if (state.verbose) fprintf(stderr, "Starting component connection stage\n"); camera_preview_port = state.camera_component->output[MMAL_CAMERA_PREVIEW_PORT]; camera_video_port = state.camera_component->output[MMAL_CAMERA_VIDEO_PORT]; camera_still_port = state.camera_component->output[MMAL_CAMERA_CAPTURE_PORT]; preview_input_port = state.preview_parameters.preview_component->input[0]; encoder_input_port = state.encoder_component->input[0]; encoder_output_port = state.encoder_component->output[0]; if (state.preview_parameters.wantPreview ) { if (state.verbose) { fprintf(stderr, "Connecting camera preview port to preview input port\n"); fprintf(stderr, "Starting video preview\n"); } // Connect camera to preview status = connect_ports(camera_preview_port, preview_input_port, &state.preview_connection); } else { status = MMAL_SUCCESS; } if (status == MMAL_SUCCESS) { if (state.verbose) fprintf(stderr, "Connecting camera stills port to encoder input port\n"); // Now connect the camera to the encoder status = connect_ports(camera_video_port, encoder_input_port, &state.encoder_connection); if (status != MMAL_SUCCESS) { vcos_log_error("%s: Failed to connect camera video port to encoder input", __func__); goto error; } if (state.filename) { if (state.filename[0] == '-') { output_file = stdout; // Ensure we don't upset the output stream with diagnostics/info state.verbose = 0; } else { if (state.verbose) fprintf(stderr, "Opening output file \"%s\"\n", state.filename); output_file = fopen(state.filename, "wb"); } if (!output_file) { // Notify user, carry on but discarding encoded output buffers vcos_log_error("%s: Error opening output file: %s\nNo output file will be generated\n", __func__, state.filename); } } // Set up our userdata - this is passed though to the callback where we need the information. callback_data.file_handle = output_file; callback_data.image = Mat(Size(state.width, state.height), CV_8UC1); callback_data.pstate = &state; callback_data.abort = 0; encoder_output_port->userdata = (struct MMAL_PORT_USERDATA_T *)&callback_data; if (state.verbose) fprintf(stderr, "Enabling encoder output port\n"); // Enable the encoder output port and tell it its callback function status = mmal_port_enable(encoder_output_port, encoder_buffer_callback); if (status != MMAL_SUCCESS) { vcos_log_error("Failed to setup encoder output"); goto error; } if (state.demoMode) { // Run for the user specific time.. int num_iterations = state.timeout / state.demoInterval; int i; if (state.verbose) fprintf(stderr, "Running in demo mode\n"); for (i=0;state.timeout == 0 || i<num_iterations;i++) { raspicamcontrol_cycle_test(state.camera_component); vcos_sleep(state.demoInterval); } } else { // Only encode stuff if we have a filename and it opened if (output_file) { int wait; if (state.verbose) fprintf(stderr, "Starting video capture\n"); if (mmal_port_parameter_set_boolean(camera_video_port, MMAL_PARAMETER_CAPTURE, 1) != MMAL_SUCCESS) { goto error; } // Send all the buffers to the encoder output port { int num = mmal_queue_length(state.encoder_pool->queue); int q; for (q=0;q<num;q++) { MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(state.encoder_pool->queue); if (!buffer) vcos_log_error("Unable to get a required buffer %d from pool queue", q); if (mmal_port_send_buffer(encoder_output_port, buffer)!= MMAL_SUCCESS) vcos_log_error("Unable to send a buffer to encoder output port (%d)", q); } } // Now wait until we need to stop. Whilst waiting we do need to check to see if we have aborted (for example // out of storage space) // Going to check every ABORT_INTERVAL milliseconds for (wait = 0; state.timeout == 0 || wait < state.timeout; wait+= ABORT_INTERVAL) { vcos_sleep(ABORT_INTERVAL); if (callback_data.abort) break; } if (state.verbose) fprintf(stderr, "Finished capture\n"); } else { if (state.timeout) vcos_sleep(state.timeout); else for (;;) vcos_sleep(ABORT_INTERVAL); } } } else { mmal_status_to_int(status); vcos_log_error("%s: Failed to connect camera to preview", __func__); } error: mmal_status_to_int(status); if (state.verbose) fprintf(stderr, "Closing down\n"); // Disable all our ports that are not handled by connections check_disable_port(camera_still_port); check_disable_port(encoder_output_port); if (state.preview_parameters.wantPreview ) mmal_connection_destroy(state.preview_connection); mmal_connection_destroy(state.encoder_connection); // Can now close our file. Note disabling ports may flush buffers which causes // problems if we have already closed the file! if (output_file && output_file != stdout) fclose(output_file); /* Disable components */ if (state.encoder_component) mmal_component_disable(state.encoder_component); if (state.preview_parameters.preview_component) mmal_component_disable(state.preview_parameters.preview_component); if (state.camera_component) mmal_component_disable(state.camera_component); destroy_encoder_component(&state); raspipreview_destroy(&state.preview_parameters); destroy_camera_component(&state); if (state.verbose) fprintf(stderr, "Close down completed, all components disconnected, disabled and destroyed\n\n"); } if (status != MMAL_SUCCESS) raspicamcontrol_check_configuration(128); return 0; }
/** * buffer header callback function for encoder * * Callback will dump buffer data to the specific file * * @param port Pointer to port from which callback originated * @param buffer mmal buffer header pointer */ static void encoder_buffer_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) { MMAL_BUFFER_HEADER_T *new_buffer; static int64_t base_time = -1; //fprintf(stderr,"*");fflush(stderr); // All our segment times based on the receipt of the first encoder callback if (base_time == -1) base_time = vcos_getmicrosecs64()/1000; // We pass our file handle and other stuff in via the userdata field. PORT_USERDATA *pData = (PORT_USERDATA *)port->userdata; if (pData) { int bytes_written = buffer->length; int64_t current_time = vcos_getmicrosecs64()/1000; vcos_assert(pData->file_handle); if(pData->pstate->inlineMotionVectors) vcos_assert(pData->imv_file_handle); //else //{ // For segmented record mode, we need to see if we have exceeded our time/size, // but also since we have inline headers turned on we need to break when we get one to // ensure that the new stream has the header in it. If we break on an I-frame, the // SPS/PPS header is actually in the previous chunk. /*if ((buffer->flags & MMAL_BUFFER_HEADER_FLAG_CONFIG) && ((pData->pstate->segmentSize && current_time > base_time + pData->pstate->segmentSize) || (pData->pstate->splitWait && pData->pstate->splitNow))) { FILE *new_handle; base_time = current_time; pData->pstate->splitNow = 0; pData->pstate->segmentNumber++; // Only wrap if we have a wrap point set if (pData->pstate->segmentWrap && pData->pstate->segmentNumber > pData->pstate->segmentWrap) pData->pstate->segmentNumber = 1; new_handle = open_filename(pData->pstate); if (new_handle) { fclose(pData->file_handle); pData->file_handle = new_handle; } new_handle = open_imv_filename(pData->pstate); if (new_handle) { fclose(pData->imv_file_handle); pData->imv_file_handle = new_handle; } }*/ if (buffer->length) { //printf("writing..."); mmal_buffer_header_mem_lock(buffer); if(buffer->flags & MMAL_BUFFER_HEADER_FLAG_CODECSIDEINFO) { if(pData->pstate->inlineMotionVectors) { bytes_written = fwrite(buffer->data, 1, buffer->length, pData->imv_file_handle); } else { //We do not want to save inlineMotionVectors... bytes_written = buffer->length; } } else { bytes_written = fwrite(buffer->data, 1, buffer->length, pData->file_handle); } mmal_buffer_header_mem_unlock(buffer); if (bytes_written != buffer->length) { vcos_log_error("Failed to write buffer data (%d from %d)- aborting", bytes_written, buffer->length); pData->abort = 1; } } //} } else { vcos_log_error("Received a encoder buffer callback with no state"); } // release buffer back to the pool mmal_buffer_header_release(buffer); // and send one back to the port (if still open) if (port->is_enabled) { MMAL_STATUS_T status; new_buffer = mmal_queue_get(pData->pstate->encoder_pool->queue); if (new_buffer) status = mmal_port_send_buffer(port, new_buffer); if (!new_buffer || status != MMAL_SUCCESS) vcos_log_error("Unable to return a buffer to the encoder port"); } //printf("done.\n"); }
/** * main */ int main(int argc, const char **argv) { // *** MODIFICATION: OpenCV modifications. // Load previous image. IplImage* prevImage = cvLoadImage("motion1.jpg", CV_LOAD_IMAGE_COLOR); // Create two arrays with the same number of channels than the original one. avg1 = cvCreateMat(prevImage->height,prevImage->width,CV_32FC3); avg2 = cvCreateMat(prevImage->height,prevImage->width,CV_32FC3); // Create image of 32 bits. IplImage* image32 = cvCreateImage(cvSize(prevImage->width,prevImage->height), 32,3); // Convert image to 32 bits. cvConvertScale(prevImage,image32,1/255,0); // Set data from previous image into arrays. cvSetData(avg1,image32->imageData,image32->widthStep); cvSetData(avg2,image32->imageData,image32->widthStep); // *** MODIFICATION end // Our main data storage vessel.. RASPISTILL_STATE state; MMAL_STATUS_T status = MMAL_SUCCESS; MMAL_PORT_T *camera_preview_port = NULL; MMAL_PORT_T *camera_video_port = NULL; MMAL_PORT_T *camera_still_port = NULL; MMAL_PORT_T *preview_input_port = NULL; MMAL_PORT_T *encoder_input_port = NULL; MMAL_PORT_T *encoder_output_port = NULL; bcm_host_init(); // Register our application with the logging system vcos_log_register("fast", VCOS_LOG_CATEGORY); signal(SIGINT, signal_handler); default_status(&state); if (state.verbose) { fprintf(stderr, "\n%s Camera App %s\n\n", basename(argv[0]), VERSION_STRING); } // OK, we have a nice set of parameters. Now set up our components // We have three components. Camera, Preview and encoder. // Camera and encoder are different in stills/video, but preview // is the same so handed off to a separate module if ((status = create_camera_component(&state)) != MMAL_SUCCESS) { vcos_log_error("%s: Failed to create camera component", __func__); } else if ((status = raspipreview_create(&state.preview_parameters)) != MMAL_SUCCESS) { vcos_log_error("%s: Failed to create preview component", __func__); destroy_camera_component(&state); } else if ((status = create_encoder_component(&state)) != MMAL_SUCCESS) { vcos_log_error("%s: Failed to create encode component", __func__); raspipreview_destroy(&state.preview_parameters); destroy_camera_component(&state); } else { PORT_USERDATA callback_data; if (state.verbose) fprintf(stderr, "Starting component connection stage\n"); camera_preview_port = state.camera_component->output[MMAL_CAMERA_PREVIEW_PORT]; camera_video_port = state.camera_component->output[MMAL_CAMERA_VIDEO_PORT]; camera_still_port = state.camera_component->output[MMAL_CAMERA_CAPTURE_PORT]; preview_input_port = state.preview_parameters.preview_component->input[0]; encoder_input_port = state.encoder_component->input[0]; encoder_output_port = state.encoder_component->output[0]; if (state.preview_parameters.wantPreview ) { if (state.verbose) { fprintf(stderr, "Connecting camera preview port to preview input port\n"); fprintf(stderr, "Starting video preview\n"); } // *** USER: remove preview // Connect camera to preview //status = connect_ports(camera_preview_port, preview_input_port, &state.preview_connection); } else { status = MMAL_SUCCESS; } if (status == MMAL_SUCCESS) { VCOS_STATUS_T vcos_status; if (state.verbose) fprintf(stderr, "Connecting camera stills port to encoder input port\n"); // Now connect the camera to the encoder status = connect_ports(camera_still_port, encoder_input_port, &state.encoder_connection); if (status != MMAL_SUCCESS) { vcos_log_error("%s: Failed to connect camera video port to encoder input", __func__); goto error; } // Set up our userdata - this is passed though to the callback where we need the information. // Null until we open our filename callback_data.file_handle = NULL; callback_data.pstate = &state; vcos_status = vcos_semaphore_create(&callback_data.complete_semaphore, "RaspiStill-sem", 0); vcos_assert(vcos_status == VCOS_SUCCESS); if (status != MMAL_SUCCESS) { vcos_log_error("Failed to setup encoder output"); goto error; } FILE *output_file = NULL; int frame = 1; // Enable the encoder output port encoder_output_port->userdata = (struct MMAL_PORT_USERDATA_T *)&callback_data; if (state.verbose) fprintf(stderr, "Enabling encoder output port\n"); // Enable the encoder output port and tell it its callback function status = mmal_port_enable(encoder_output_port, encoder_buffer_callback); // Create an empty matrix with the size of the buffer. CvMat* buf = cvCreateMat(1,60000,CV_8UC1); // Keep buffer that gets frames from queue. MMAL_BUFFER_HEADER_T *buffer; // Image to be displayed. IplImage* image; // Keep number of buffers and index for the loop. int num, q; while(1) { // Send all the buffers to the encoder output port num = mmal_queue_length(state.encoder_pool->queue); for (q=0;q<num;q++) { buffer = mmal_queue_get(state.encoder_pool->queue); if (!buffer) vcos_log_error("Unable to get a required buffer %d from pool queue", q); if (mmal_port_send_buffer(encoder_output_port, buffer)!= MMAL_SUCCESS) vcos_log_error("Unable to send a buffer to encoder output port (%d)", q); } // for if (mmal_port_parameter_set_boolean(camera_still_port, MMAL_PARAMETER_CAPTURE, 1) != MMAL_SUCCESS) vcos_log_error("%s: Failed to start capture", __func__); else { // Wait for capture to complete // For some reason using vcos_semaphore_wait_timeout sometimes returns immediately with bad parameter error // even though it appears to be all correct, so reverting to untimed one until figure out why its erratic vcos_semaphore_wait(&callback_data.complete_semaphore); if (state.verbose) fprintf(stderr, "Finished capture %d\n", frame); } // else // Copy buffer from camera to matrix. buf->data.ptr = buffer->data; // This workaround is needed for the code to work // *** TODO: investigate why. printf("Until here works\n"); // Decode the image and display it. image = cvDecodeImage(buf, CV_LOAD_IMAGE_COLOR); // Destinations CvMat* res1 = cvCreateMat(image->height,image->width,CV_8UC3); CvMat* res2 = cvCreateMat(image->height,image->width,CV_8UC3); // Update running averages and then scale, calculate absolute values // and convert the result 8-bit. // *** USER:change the value of the weight. cvRunningAvg(image,avg2,0.0001, NULL); cvConvertScaleAbs(avg2, res2, 1,0); cvRunningAvg(image,avg1,0.1, NULL); cvConvertScaleAbs(avg1, res1, 1,0); // Show images cvShowImage("img",image); cvShowImage("avg1",res1); cvShowImage("avg2",res2); cvWaitKey(20); // Update previous image. cvSaveImage("motion1.jpg", image, 0); } // end while vcos_semaphore_delete(&callback_data.complete_semaphore); } else { mmal_status_to_int(status); vcos_log_error("%s: Failed to connect camera to preview", __func__); } error: mmal_status_to_int(status); if (state.verbose) fprintf(stderr, "Closing down\n"); // Disable all our ports that are not handled by connections check_disable_port(camera_video_port); check_disable_port(encoder_output_port); if (state.preview_parameters.wantPreview ) mmal_connection_destroy(state.preview_connection); mmal_connection_destroy(state.encoder_connection); /* Disable components */ if (state.encoder_component) mmal_component_disable(state.encoder_component); if (state.preview_parameters.preview_component) mmal_component_disable(state.preview_parameters.preview_component); if (state.camera_component) mmal_component_disable(state.camera_component); destroy_encoder_component(&state); raspipreview_destroy(&state.preview_parameters); destroy_camera_component(&state); if (state.verbose) fprintf(stderr, "Close down completed, all components disconnected, disabled and destroyed\n\n"); } if (status != MMAL_SUCCESS) raspicamcontrol_check_configuration(128); return 0; }
MmalStillCamera::MmalStillCamera(int imageWidth, int imageHeight, bool enableBurstMode) : m_imageWidth(imageWidth), m_imageHeight(imageHeight), m_callbackData(NULL), m_cs(), m_camera(NULL), m_preview(NULL), m_encoder(NULL), m_pool(NULL), m_previewPort(NULL), m_videoPort(NULL), m_stillPort(NULL), m_targetPort(NULL) { m_callbackData = new MmalStillCallbackData(m_imageWidth, m_imageHeight, 3); createCameraComponent(); std::cout << "Created camera" << std::endl; createPreview(); std::cout << "Created preview" << std::endl; std::cout << "Target Image Width: " << VCOS_ALIGN_UP(m_imageWidth, 32) << std::endl; std::cout << "Target Image Height: " << VCOS_ALIGN_UP(m_imageHeight, 16) << std::endl; MMAL_STATUS_T status; m_targetPort = m_stillPort; // Create pool of buffer headers for the output port to consume m_pool = mmal_port_pool_create(m_targetPort, m_targetPort->buffer_num, m_targetPort->buffer_size); if (m_pool == NULL) { throw Exception("Failed to create buffer header pool for encoder output port"); } MMAL_CONNECTION_T *preview_connection = NULL; status = connect_ports(m_previewPort, m_preview->input[0], &preview_connection); if (status != MMAL_SUCCESS) { throw Exception("Error connecting preview port"); } m_targetPort->userdata = (struct MMAL_PORT_USERDATA_T *) m_callbackData; m_callbackData->image = NULL; m_callbackData->pool = m_pool; // Enable the encoder output port and tell it its callback function if (mmal_port_enable(m_targetPort, EncoderBufferCallback) != MMAL_SUCCESS) { std::cerr << "Error enabling the encoder buffer callback" << std::endl; } // Send all the buffers to the encoder output port int num = mmal_queue_length(m_pool->queue); for (int q = 0; q < num; q++) { MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(m_pool->queue); if (buffer == NULL) { std::cerr << "Unable to get buffer " << q << " from the pool" << std::endl; } if (mmal_port_send_buffer(m_targetPort, buffer)!= MMAL_SUCCESS) { std::cerr << "Unable to send a buffer " << q << " to encoder output port " << std::endl; } } // Enable burst mode if (enableBurstMode) { if (mmal_port_parameter_set_boolean(m_camera->control, MMAL_PARAMETER_CAMERA_BURST_CAPTURE, 1) != MMAL_SUCCESS) { std::cerr << "Error enabling burst mode" << std::endl; } std::cout << "Enabled burst mode for still images" << std::endl; } std::cout << "Initialized camera" << std::endl; }
static void camera_video_buffer_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) { static int frame_count = 0; static struct timespec t1; struct timespec t2; uint8_t *local_overlay_buffer; //fprintf(stderr, "INFO:%s\n", __func__); if (frame_count == 0) { clock_gettime(CLOCK_MONOTONIC, &t1); } clock_gettime(CLOCK_MONOTONIC, &t2); int d = t2.tv_sec - t1.tv_sec; MMAL_BUFFER_HEADER_T *new_buffer; MMAL_BUFFER_HEADER_T *output_buffer = 0; PORT_USERDATA *userdata = (PORT_USERDATA *) port->userdata; MMAL_POOL_T *pool = userdata->camera_video_port_pool; frame_count++; output_buffer = mmal_queue_get(userdata->encoder_input_pool->queue); //Set pointer to latest updated/drawn double buffer to local pointer if (userdata->overlay == 0) { local_overlay_buffer = userdata->overlay_buffer; } else { local_overlay_buffer = userdata->overlay_buffer2; } //Try to some colors http://en.wikipedia.org/wiki/YUV int chrominance_offset = userdata->width * userdata->height; int v_offset = chrominance_offset / 4; int chroma = 0; if (output_buffer) { mmal_buffer_header_mem_lock(buffer); memcpy(output_buffer->data, buffer->data, buffer->length); // dim int x, y; for (x = 0; x < 600; x++) { for (y = 0; y < 100; y++) { if (local_overlay_buffer[(y * 600 + x) * 4] > 0) { //copy luma Y output_buffer->data[y * userdata->width + x ] = 0xdf; //pointer to chrominance U/V chroma= y / 2 * userdata->width / 2 + x / 2 + chrominance_offset; //just guessing colors output_buffer->data[chroma] = 0x38 ; output_buffer->data[chroma+v_offset] = 0xb8 ; } } } output_buffer->length = buffer->length; mmal_buffer_header_mem_unlock(buffer); if (mmal_port_send_buffer(userdata->encoder_input_port, output_buffer) != MMAL_SUCCESS) { fprintf(stderr, "ERROR: Unable to send buffer \n"); } } else { fprintf(stderr, "ERROR: mmal_queue_get (%d)\n", output_buffer); } if (frame_count % 10 == 0) { // print framerate every n frame clock_gettime(CLOCK_MONOTONIC, &t2); float d = (t2.tv_sec + t2.tv_nsec / 1000000000.0) - (t1.tv_sec + t1.tv_nsec / 1000000000.0); float fps = 0.0; if (d > 0) { fps = frame_count / d; } else { fps = frame_count; } userdata->fps = fps; //fprintf(stderr, " Frame = %d, Framerate = %.1f fps \n", frame_count, fps); } mmal_buffer_header_release(buffer); // and send one back to the port (if still open) if (port->is_enabled) { MMAL_STATUS_T status; new_buffer = mmal_queue_get(pool->queue); if (new_buffer) { status = mmal_port_send_buffer(port, new_buffer); } if (!new_buffer || status != MMAL_SUCCESS) { fprintf(stderr, "Error: Unable to return a buffer to the video port\n"); } } }
static void encoder_buffer_callback( MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer ) { MMAL_BUFFER_HEADER_T *new_buffer; static int buffer_count = 0; static sSX_CAMERA_HW_BUFFER *hw_buf = NULL; static unsigned index = 0; // We pass our file handle and other stuff in via the userdata field. printf("callback current time = %d\n", get_time_ns()); PORT_USERDATA *pData = (PORT_USERDATA *) port->userdata; assert(pData != NULL); int bytes_written = buffer->length; vcos_assert(pData->file_handle); assert(buffer->length > 0); // Get frame end. unsigned char frame_end = 0; if(buffer->flags & MMAL_BUFFER_HEADER_FLAG_FRAME_END) { frame_end = 1; } unsigned char config = 0; if(buffer->flags & MMAL_BUFFER_HEADER_FLAG_CONFIG) { config = 1; } #if 0 printf("frame_end = %d\n", buffer->flags & MMAL_BUFFER_HEADER_FLAG_FRAME_END); printf("config = %d\n", buffer->flags & MMAL_BUFFER_HEADER_FLAG_CONFIG); printf("buffer received: len = %d, frame_end = %d\n", buffer->length, frame_end); #endif if(hw_buf == NULL) { index = 0; hw_buf = malloc(sizeof(sSX_CAMERA_HW_BUFFER)); } mmal_buffer_header_mem_lock(buffer); unsigned int offset = 0; if( (buffer->data[0] == 0x00) && (buffer->data[1] == 0x00) && (buffer->data[2] == 0x00) && (buffer->data[3] == 0x01)) { offset = 4; } assert((index + buffer->length) <= SX_CAMERA_HW_NAL_LEN_MAX); memcpy(&hw_buf->nal[index], buffer->data + offset, buffer->length - offset); index += (buffer->length - offset); mmal_buffer_header_mem_unlock(buffer); // release buffer back to the pool mmal_buffer_header_release(buffer); if(frame_end || config) { hw_buf->nal_len = index; sx_queue_push(f_nal_queue, hw_buf); hw_buf = NULL; // printf("(sx_camera_hw): Queue nal unit [len = %d]\n", index); } #if 0 printf("frame end = %d\n", frame_end); printf("data len = %d\n", buffer->length); printf("0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", buffer->data[0], buffer->data[1], buffer->data[2], buffer->data[3], buffer->data[4], buffer->data[5], buffer->data[6], buffer->data[7]); mmal_buffer_header_mem_lock(buffer); bytes_written = fwrite(buffer->data, 1, buffer->length, pData->file_handle); mmal_buffer_header_mem_unlock(buffer); #endif // and send one back to the port (if still open) if (port->is_enabled) { MMAL_STATUS_T status; new_buffer = mmal_queue_get(pData->pstate->encoder_pool->queue); if (new_buffer) { status = mmal_port_send_buffer(port, new_buffer); assert(status == MMAL_SUCCESS); } } }
void camera_thread( void ) { static MMAL_STATUS_T status; static RASPIVID_STATE state; static MMAL_PORT_T *camera_preview_port = NULL; static MMAL_PORT_T *camera_video_port = NULL; static MMAL_PORT_T *camera_still_port = NULL; static MMAL_PORT_T *preview_input_port = NULL; static MMAL_PORT_T *encoder_input_port = NULL; static MMAL_PORT_T *encoder_output_port = NULL; static FILE *output_file = NULL; f_nal_queue = sx_queue_create(); bcm_host_init(); default_status(&state); state.verbose = 1; status = create_camera_component(&state); assert(status == MMAL_SUCCESS); status = raspipreview_create(&state.preview_parameters); assert(status == MMAL_SUCCESS); status = create_encoder_component(&state); assert(status == MMAL_SUCCESS); PORT_USERDATA callback_data; camera_preview_port = state.camera_component->output[MMAL_CAMERA_PREVIEW_PORT]; camera_video_port = state.camera_component->output[MMAL_CAMERA_VIDEO_PORT]; camera_still_port = state.camera_component->output[MMAL_CAMERA_CAPTURE_PORT]; preview_input_port = state.preview_parameters.preview_component->input[0]; encoder_input_port = state.encoder_component->input[0]; encoder_output_port = state.encoder_component->output[0]; // Now connect the camera to the encoder status = connect_ports(camera_video_port, encoder_input_port, &state.encoder_connection); assert(status == MMAL_SUCCESS); char *filename = "output.h264"; state.filename = filename; output_file = fopen(state.filename, "wb"); // Set up our userdata - this is passed though to the callback where we need the information. callback_data.file_handle = output_file; callback_data.pstate = &state; callback_data.abort = 0; encoder_output_port->userdata = (struct MMAL_PORT_USERDATA_T *) &callback_data; // Enable the encoder output port and tell it its callback function status = mmal_port_enable(encoder_output_port, encoder_buffer_callback); assert(status == MMAL_SUCCESS); // Only encode stuff if we have a filename and it opened if (output_file) { int wait; if (state.verbose) fprintf(stderr, "Starting video capture\n"); status = mmal_port_parameter_set_boolean(camera_video_port, MMAL_PARAMETER_CAPTURE, 1); assert(status == MMAL_SUCCESS); // Send all the buffers to the encoder output port { int num = mmal_queue_length(state.encoder_pool->queue); int q; fprintf(stderr, "mmal_queue_len = %d\n", num); for (q=0;q<num;q++) { printf("start current time = %d\n", get_time_ns()); MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(state.encoder_pool->queue); assert(buffer != NULL); status = mmal_port_send_buffer(encoder_output_port, buffer); assert(status == MMAL_SUCCESS); } } // Now wait until we need to stop. Whilst waiting we do need to check to see if we have aborted (for example // out of storage space) // Going to check every ABORT_INTERVAL milliseconds #if 1 while(1) { // sleep forever. vcos_sleep(ABORT_INTERVAL); } #endif #if 0 for (wait = 0; state.timeout == 0 || wait < state.timeout; wait+= ABORT_INTERVAL) { vcos_sleep(ABORT_INTERVAL); if (callback_data.abort) { fprintf(stderr, "333\n"); break; } fprintf(stderr, "222\n"); } fprintf(stderr, "wait = %u\n", wait); if (state.verbose) fprintf(stderr, "Finished capture\n"); #endif } }
static picture_t *decode(decoder_t *dec, block_t **pblock) { decoder_sys_t *sys = dec->p_sys; block_t *block; MMAL_BUFFER_HEADER_T *buffer; bool need_flush = false; uint32_t len; uint32_t flags = 0; MMAL_STATUS_T status; picture_t *ret = NULL; /* * Configure output port if necessary */ if (sys->output_format) { if (change_output_format(dec) < 0) msg_Err(dec, "Failed to change output port format"); } if (!pblock) goto out; block = *pblock; /* * Check whether full flush is required */ if (block && block->i_flags & BLOCK_FLAG_DISCONTINUITY) { flush_decoder(dec); block_Release(*pblock); return NULL; } /* * Send output buffers */ if (atomic_load(&sys->started)) { buffer = mmal_queue_get(sys->decoded_pictures); if (buffer) { ret = (picture_t *)buffer->user_data; ret->date = buffer->pts; ret->b_progressive = sys->b_progressive; ret->b_top_field_first = sys->b_top_field_first; if (sys->output_pool) { buffer->data = NULL; mmal_buffer_header_reset(buffer); mmal_buffer_header_release(buffer); } } fill_output_port(dec); } if (ret) goto out; /* * Process input */ if (!block) goto out; *pblock = NULL; if (block->i_flags & BLOCK_FLAG_CORRUPTED) flags |= MMAL_BUFFER_HEADER_FLAG_CORRUPTED; vlc_mutex_lock(&sys->mutex); while (block->i_buffer > 0) { buffer = mmal_queue_timedwait(sys->input_pool->queue, 2); if (!buffer) { msg_Err(dec, "Failed to retrieve buffer header for input data"); need_flush = true; break; } mmal_buffer_header_reset(buffer); buffer->cmd = 0; buffer->pts = block->i_pts != 0 ? block->i_pts : block->i_dts; buffer->dts = block->i_dts; buffer->alloc_size = sys->input->buffer_size; len = block->i_buffer; if (len > buffer->alloc_size) len = buffer->alloc_size; buffer->data = block->p_buffer; block->p_buffer += len; block->i_buffer -= len; buffer->length = len; if (block->i_buffer == 0) buffer->user_data = block; buffer->flags = flags; status = mmal_port_send_buffer(sys->input, buffer); if (status != MMAL_SUCCESS) { msg_Err(dec, "Failed to send buffer to input port (status=%"PRIx32" %s)", status, mmal_status_to_string(status)); break; } atomic_fetch_add(&sys->input_in_transit, 1); } vlc_mutex_unlock(&sys->mutex); out: if (need_flush) flush_decoder(dec); return ret; }
int main(int argc, char **argv) { MMAL_COMPONENT_T *camera =0; MMAL_COMPONENT_T *preview=0; MMAL_COMPONENT_T *encoder=0; MMAL_CONNECTION_T *preview_conn=0; MMAL_CONNECTION_T *encoder_conn=0; USERDATA_T callback_data; // bcm should be initialized before any GPU call is made bcm_host_init(); setNonDefaultOptions(argc, argv); // Open file to save the video open_new_file_handle(&callback_data, output_file_name); fprintf(stderr, "Output Filename: %s\n", output_file_name); // Create Camera, set default values and enable it vcos_assert((mmal_component_create(MMAL_COMPONENT_DEFAULT_CAMERA, &camera) == MMAL_SUCCESS) && "Failed creating camera component"); vcos_assert((set_camera_component_defaults(camera)) == MMAL_SUCCESS && "Failed setting camera components default values"); vcos_assert((mmal_component_enable(camera) == MMAL_SUCCESS) && "Failed to enable camera component"); // Create Preview, set default values and enable it vcos_assert((mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_RENDERER, &preview) == MMAL_SUCCESS) && "Failed creating preview component"); vcos_assert((set_preview_component_defaults(preview) == MMAL_SUCCESS) && "Failed setting preview components default values"); vcos_assert((mmal_component_enable(preview) == MMAL_SUCCESS) && "Failed to enable camera component"); // Create Encoder, set defaults, enable it and create encoder pool vcos_assert((mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_ENCODER, &encoder) == MMAL_SUCCESS) && "Failed to create encoder component"); vcos_assert((encoder->input_num && encoder->output_num) && "Video encoder does not have input/output ports\n"); set_encoder_component_defaults(encoder); vcos_assert((mmal_component_enable(encoder) == MMAL_SUCCESS) && "Failed enabling encoder component"); callback_data.pool = (MMAL_POOL_T *)mmal_port_pool_create(encoder->output[0], encoder->output[0]->buffer_num, encoder->output[0]->buffer_size); vcos_assert(callback_data.pool && "Failed creating encoder pool\n"); // Setup connections vcos_assert((mmal_connection_create(&preview_conn, camera->output[0], preview->input[0], MMAL_CONNECTION_FLAG_TUNNELLING | MMAL_CONNECTION_FLAG_ALLOCATION_ON_INPUT) == MMAL_SUCCESS) && "Failed stablishing connection between camera output 0 and preview"); vcos_assert((mmal_connection_enable(preview_conn) == MMAL_SUCCESS) && "Failed enabling connection between camera output 0 and preview"); vcos_assert((mmal_connection_create(&encoder_conn, camera->output[1], encoder->input[0], // MMAL_CONNECTION_FLAG_TUNNELLING | MMAL_CONNECTION_FLAG_ALLOCATION_ON_INPUT) == MMAL_SUCCESS) MMAL_CONNECTION_FLAG_ALLOCATION_ON_INPUT) == MMAL_SUCCESS) && "Failed creating encoder connection to capture (camera output 1)"); vcos_assert((mmal_connection_enable(encoder_conn) == MMAL_SUCCESS) && "Failed enabling encoder connection to capture (campera output 1)"); encoder_conn->callback = connection_video2encoder_callback; // Set callback and enable encoder port encoder->output[0]->userdata = (struct MMAL_PORT_USERDATA_T *)&callback_data; vcos_assert(MMAL_SUCCESS == mmal_port_enable(encoder->output[0], encoder_callback)); // Send the buffer to encode output port MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(callback_data.pool->queue); vcos_assert((mmal_port_send_buffer(encoder->output[0], buffer)== MMAL_SUCCESS) && "Unable to send buffer to encoder output port"); vcos_assert((mmal_port_parameter_set_boolean(camera->output[1], MMAL_PARAMETER_CAPTURE, 1) == MMAL_SUCCESS) && "Unable to set camera->output[1] capture parameter"); consume_queue_on_connection(encoder_conn->out, encoder_conn->pool->queue); while(1) { vcos_sleep(1000); // wait for exit call if (exit_prog){ vcos_sleep(500); // exit called, wait for all buffers be flushed break; } } return 0; }
/** * buffer header callback function for video * * @param port Pointer to port from which callback originated * @param buffer mmal buffer header pointer */ static void video_buffer_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) { MMAL_BUFFER_HEADER_T *new_buffer; PORT_USERDATA *pData = (PORT_USERDATA *)port->userdata; if (pData) { if (buffer->length) { mmal_buffer_header_mem_lock(buffer); // // *** PR : OPEN CV Stuff here ! // int w=pData->pstate->width; // get image size int h=pData->pstate->height; int h4=h/4; memcpy(py->imageData,buffer->data,w*h); // read Y if (pData->pstate->graymode==0) { memcpy(pu->imageData,buffer->data+w*h,w*h4); // read U memcpy(pv->imageData,buffer->data+w*h+w*h4,w*h4); // read v cvResize(pu, pu_big, CV_INTER_NN); cvResize(pv, pv_big, CV_INTER_NN); //CV_INTER_LINEAR looks better but it's slower cvMerge(py, pu_big, pv_big, NULL, image); cvCvtColor(image,dstImage,CV_YCrCb2RGB); // convert in RGB color space (slow) cvShowImage("camcvWin", dstImage ); } else { cvShowImage("camcvWin", py); // display only gray channel } cvWaitKey(1); nCount++; // count frames displayed mmal_buffer_header_mem_unlock(buffer); } else vcos_log_error("buffer null"); } else { vcos_log_error("Received a encoder buffer callback with no state"); } // release buffer back to the pool mmal_buffer_header_release(buffer); // and send one back to the port (if still open) if (port->is_enabled) { MMAL_STATUS_T status; new_buffer = mmal_queue_get(pData->pstate->video_pool->queue); if (new_buffer) status = mmal_port_send_buffer(port, new_buffer); if (!new_buffer || status != MMAL_SUCCESS) vcos_log_error("Unable to return a buffer to the encoder port"); } }
RaspiCamCvCapture * raspiCamCvCreateCameraCapture(int index) { RaspiCamCvCapture * capture = (RaspiCamCvCapture*)malloc(sizeof(RaspiCamCvCapture)); // Our main data storage vessel.. RASPIVID_STATE * state = (RASPIVID_STATE*)malloc(sizeof(RASPIVID_STATE)); capture->pState = state; MMAL_STATUS_T status = -1; MMAL_PORT_T *camera_video_port = NULL; MMAL_PORT_T *camera_video_port_2 = NULL; //MMAL_PORT_T *camera_still_port = NULL; MMAL_PORT_T *encoder_input_port = NULL; MMAL_PORT_T *encoder_output_port = NULL; bcm_host_init(); // read default status default_status(state); int w = state->width; int h = state->height; state->py = cvCreateImage(cvSize(w,h), IPL_DEPTH_8U, 3); // Y component of YUV I420 frame if (state->graymode==0) { state->pu = cvCreateImage(cvSize(w/2,h/2), IPL_DEPTH_8U, 1); // U component of YUV I420 frame state->pv = cvCreateImage(cvSize(w/2,h/2), IPL_DEPTH_8U, 1); // V component of YUV I420 frame } vcos_semaphore_create(&state->capture_sem, "Capture-Sem", 0); vcos_semaphore_create(&state->capture_done_sem, "Capture-Done-Sem", 0); if (state->graymode==0) { state->pu_big = cvCreateImage(cvSize(w,h), IPL_DEPTH_8U, 1); state->pv_big = cvCreateImage(cvSize(w,h), IPL_DEPTH_8U, 1); state->yuvImage = cvCreateImage(cvSize(w,h), IPL_DEPTH_8U, 3); state->dstImage = cvCreateImage(cvSize(w,h), IPL_DEPTH_8U, 3); // final picture to display } //printf("point2.0\n"); // create camera if (!create_camera_component(state)) { vcos_log_error("%s: Failed to create camera component", __func__); raspiCamCvReleaseCapture(&capture); return NULL; } else if ((status = create_encoder_component(state)) != MMAL_SUCCESS) { vcos_log_error("%s: Failed to create encode component", __func__); destroy_camera_component(state); return NULL; } //printf("point2.1\n"); //create_encoder_component(state); camera_video_port = state->camera_component->output[MMAL_CAMERA_VIDEO_PORT]; camera_video_port_2 = state->camera_component->output[MMAL_CAMERA_VIDEO_PORT_2]; //camera_still_port = state->camera_component->output[MMAL_CAMERA_CAPTURE_PORT]; encoder_input_port = state->encoder_component->input[0]; encoder_output_port = state->encoder_component->output[0]; // assign data to use for callback camera_video_port->userdata = (struct MMAL_PORT_USERDATA_T *)state; // assign data to use for callback camera_video_port_2->userdata = (struct MMAL_PORT_USERDATA_T *)state; // Now connect the camera to the encoder status = connect_ports(camera_video_port_2, encoder_input_port, &state->encoder_connection); if (state->filename) { if (state->filename[0] == '-') { state->callback_data.file_handle = stdout; } else { state->callback_data.file_handle = open_filename(state); } if (!state->callback_data.file_handle) { // Notify user, carry on but discarding encoded output buffers vcos_log_error("%s: Error opening output file: %s\nNo output file will be generated\n", __func__, state->filename); } } // Set up our userdata - this is passed though to the callback where we need the information. state->callback_data.pstate = state; state->callback_data.abort = 0; encoder_output_port->userdata = (struct MMAL_PORT_USERDATA_T *)&state->callback_data; // Enable the encoder output port and tell it its callback function status = mmal_port_enable(encoder_output_port, encoder_buffer_callback); if (status != MMAL_SUCCESS) { state->encoder_connection = NULL; vcos_log_error("%s: Failed to connect camera video port to encoder input", __func__); return NULL; } if (status != MMAL_SUCCESS) { vcos_log_error("Failed to setup encoder output"); return NULL; } //mmal_port_enable(encoder_output_port, encoder_buffer_callback); // Only encode stuff if we have a filename and it opened // Note we use the copy in the callback, as the call back MIGHT change the file handle if (state->callback_data.file_handle) { int running = 1; // Send all the buffers to the encoder output port { int num = mmal_queue_length(state->encoder_pool->queue); int q; for (q=0;q<num;q++) { MMAL_BUFFER_HEADER_T *buffer2 = mmal_queue_get(state->encoder_pool->queue); if (!buffer2) vcos_log_error("Unable to get a required buffer %d from pool queue", q); if (mmal_port_send_buffer(encoder_output_port, buffer2)!= MMAL_SUCCESS) vcos_log_error("Unable to send a buffer to encoder output port (%d)", q); } } } // start capture if (mmal_port_parameter_set_boolean(camera_video_port_2, MMAL_PARAMETER_CAPTURE, 1) != MMAL_SUCCESS) { vcos_log_error("%s: Failed to start capture", __func__); raspiCamCvReleaseCapture(&capture); return NULL; } // Send all the buffers to the video port int num = mmal_queue_length(state->video_pool->queue); int q; for (q = 0; q < num; q++) { MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(state->video_pool->queue); if (!buffer) vcos_log_error("Unable to get a required buffer %d from pool queue", q); if (mmal_port_send_buffer(camera_video_port, buffer)!= MMAL_SUCCESS) vcos_log_error("Unable to send a buffer to encoder output port (%d)", q); } //mmal_status_to_int(status); // Disable all our ports that are not handled by connections //check_disable_port(camera_still_port); //if (status != 0) // raspicamcontrol_check_configuration(128); vcos_semaphore_wait(&state->capture_done_sem); return capture; }
/** * main */ int main(int argc, const char **argv) { // Our main data storage vessel.. RASPIVID_STATE state; MMAL_STATUS_T status = -1; MMAL_PORT_T *camera_video_port = NULL; MMAL_PORT_T *camera_still_port = NULL; MMAL_PORT_T *preview_input_port = NULL; MMAL_PORT_T *encoder_input_port = NULL; MMAL_PORT_T *encoder_output_port = NULL; time_t timer_begin,timer_end; double secondsElapsed; bcm_host_init(); signal(SIGINT, signal_handler); // read default status default_status(&state); // init windows and OpenCV Stuff cvNamedWindow("camcvWin", CV_WINDOW_AUTOSIZE); int w=state.width; int h=state.height; dstImage = cvCreateImage(cvSize(w,h), IPL_DEPTH_8U, 3); py = cvCreateImage(cvSize(w,h), IPL_DEPTH_8U, 1); // Y component of YUV I420 frame pu = cvCreateImage(cvSize(w/2,h/2), IPL_DEPTH_8U, 1); // U component of YUV I420 frame pv = cvCreateImage(cvSize(w/2,h/2), IPL_DEPTH_8U, 1); // V component of YUV I420 frame pu_big = cvCreateImage(cvSize(w,h), IPL_DEPTH_8U, 1); pv_big = cvCreateImage(cvSize(w,h), IPL_DEPTH_8U, 1); image = cvCreateImage(cvSize(w,h), IPL_DEPTH_8U, 3); // final picture to display // create camera if (!create_camera_component(&state)) { vcos_log_error("%s: Failed to create camera component", __func__); } else if (!raspipreview_create(&state.preview_parameters)) { vcos_log_error("%s: Failed to create preview component", __func__); destroy_camera_component(&state); } else { PORT_USERDATA callback_data; camera_video_port = state.camera_component->output[MMAL_CAMERA_VIDEO_PORT]; camera_still_port = state.camera_component->output[MMAL_CAMERA_CAPTURE_PORT]; VCOS_STATUS_T vcos_status; callback_data.pstate = &state; vcos_status = vcos_semaphore_create(&callback_data.complete_semaphore, "RaspiStill-sem", 0); vcos_assert(vcos_status == VCOS_SUCCESS); // assign data to use for callback camera_video_port->userdata = (struct MMAL_PORT_USERDATA_T *)&callback_data; // init timer time(&timer_begin); // start capture if (mmal_port_parameter_set_boolean(camera_video_port, MMAL_PARAMETER_CAPTURE, 1) != MMAL_SUCCESS) { goto error; } // Send all the buffers to the video port int num = mmal_queue_length(state.video_pool->queue); int q; for (q=0; q<num; q++) { MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(state.video_pool->queue); if (!buffer) vcos_log_error("Unable to get a required buffer %d from pool queue", q); if (mmal_port_send_buffer(camera_video_port, buffer)!= MMAL_SUCCESS) vcos_log_error("Unable to send a buffer to encoder output port (%d)", q); } // Now wait until we need to stop vcos_sleep(state.timeout); error: mmal_status_to_int(status); // Disable all our ports that are not handled by connections check_disable_port(camera_still_port); if (state.camera_component) mmal_component_disable(state.camera_component); //destroy_encoder_component(&state); raspipreview_destroy(&state.preview_parameters); destroy_camera_component(&state); } if (status != 0) raspicamcontrol_check_configuration(128); time(&timer_end); /* get current time; same as: timer = time(NULL) */ cvReleaseImage(&dstImage); cvReleaseImage(&pu); cvReleaseImage(&pv); cvReleaseImage(&py); cvReleaseImage(&pu_big); cvReleaseImage(&pv_big); secondsElapsed = difftime(timer_end,timer_begin); printf ("%.f seconds for %d frames : FPS = %f\n", secondsElapsed,nCount,(float)((float)(nCount)/secondsElapsed)); return 0; }
/** * buffer header callback function for video * * @param port Pointer to port from which callback originated * @param buffer mmal buffer header pointer */ static void video_buffer_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) { MMAL_BUFFER_HEADER_T *new_buffer; RASPIVID_STATE * state = (RASPIVID_STATE *)port->userdata; if (state) { if (state->finished) { vcos_semaphore_post(&state->capture_done_sem); return; } if (buffer->length) { mmal_buffer_header_mem_lock(buffer); // // *** PR : OPEN CV Stuff here ! // int w=state->width; // get image size int h=state->height; int h4=h/4; memcpy(state->py->imageData,buffer->data,w*h); // read Y if (state->graymode==0) { memcpy(state->pu->imageData,buffer->data+w*h,w*h4); // read U memcpy(state->pv->imageData,buffer->data+w*h+w*h4,w*h4); // read v } vcos_semaphore_post(&state->capture_done_sem); vcos_semaphore_wait(&state->capture_sem); mmal_buffer_header_mem_unlock(buffer); } else { vcos_log_error("buffer null"); } } else { vcos_log_error("Received a encoder buffer callback with no state"); } // release buffer back to the pool mmal_buffer_header_release(buffer); // and send one back to the port (if still open) if (port->is_enabled) { MMAL_STATUS_T status; new_buffer = mmal_queue_get(state->video_pool->queue); if (new_buffer) status = mmal_port_send_buffer(port, new_buffer); if (!new_buffer || status != MMAL_SUCCESS) vcos_log_error("Unable to return a buffer to the encoder port"); } }
/** * buffer header callback function for encoder * * Callback will dump buffer data to the specific file * * @param port Pointer to port from which callback originated * @param buffer mmal buffer header pointer */ static void encoder_buffer_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) { int complete = 0; // We pass our file handle and other stuff in via the userdata field. PORT_USERDATA *pData = (PORT_USERDATA *)port->userdata; if (pData) { if (buffer->length) { mmal_buffer_header_mem_lock(buffer); // // *** PR : OPEN CV Stuff here ! // // create a CvMat empty structure, with size of the buffer. CvMat* buf = cvCreateMat(1,buffer->length,CV_8UC1); // copy buffer from cam to CvMat buf->data.ptr = buffer->data; // decode image (interpret jpg) IplImage *img = cvDecodeImage(buf, CV_LOAD_IMAGE_COLOR); // we can save it ! cvSaveImage("foobar.bmp", img,0); // or display it cvNamedWindow("camcvWin", CV_WINDOW_AUTOSIZE); cvShowImage("camcvWin", img ); cvWaitKey(0); //cvReleaseImage(&img ); mmal_buffer_header_mem_unlock(buffer); } // Now flag if we have completed if (buffer->flags & (MMAL_BUFFER_HEADER_FLAG_FRAME_END | MMAL_BUFFER_HEADER_FLAG_TRANSMISSION_FAILED)) complete = 1; } else { vcos_log_error("Received a encoder buffer callback with no state"); } // release buffer back to the pool mmal_buffer_header_release(buffer); // and send one back to the port (if still open) if (port->is_enabled) { MMAL_STATUS_T status; MMAL_BUFFER_HEADER_T *new_buffer; new_buffer = mmal_queue_get(pData->pstate->encoder_pool->queue); if (new_buffer) { status = mmal_port_send_buffer(port, new_buffer); } if (!new_buffer || status != MMAL_SUCCESS) vcos_log_error("Unable to return a buffer to the encoder port"); } if (complete) vcos_semaphore_post(&(pData->complete_semaphore)); }
/** * main */ int main(int argc, const char **argv) { // Our main data storage vessel.. RASPISTILLYUV_STATE state; MMAL_STATUS_T status; MMAL_PORT_T *camera_preview_port = NULL; MMAL_PORT_T *camera_video_port = NULL; MMAL_PORT_T *camera_still_port = NULL; MMAL_PORT_T *preview_input_port = NULL; FILE *output_file = NULL; // Register our application with the logging system vcos_log_register("RaspiStill", VCOS_LOG_CATEGORY); printf("\nRaspiStillYUV Camera App\n"); printf( "========================\n\n"); signal(SIGINT, signal_handler); // Do we have any parameters if (argc == 1) { display_valid_parameters(); exit(0); } default_status(&state); // Parse the command line and put options in to our status structure if (parse_cmdline(argc, argv, &state)) { status = -1; exit(0); } if (state.verbose) dump_status(&state); // OK, we have a nice set of parameters. Now set up our components // We have two components. Camera and Preview // Camera is different in stills/video, but preview // is the same so handed off to a separate module if (!create_camera_component(&state)) { vcos_log_error("%s: Failed to create camera component", __func__); } else if ( !raspipreview_create(&state.preview_parameters)) { vcos_log_error("%s: Failed to create preview component", __func__); destroy_camera_component(&state); } else { PORT_USERDATA callback_data; if (state.verbose) printf("Starting component connection stage\n"); camera_preview_port = state.camera_component->output[MMAL_CAMERA_PREVIEW_PORT]; camera_video_port = state.camera_component->output[MMAL_CAMERA_VIDEO_PORT]; camera_still_port = state.camera_component->output[MMAL_CAMERA_CAPTURE_PORT]; preview_input_port = state.preview_parameters.preview_component->input[0]; if (state.preview_parameters.wantPreview ) { if (state.verbose) { printf("Connecting camera preview port to preview input port\n"); printf("Starting video preview\n"); } // Connect camera to preview status = connect_ports(camera_preview_port, preview_input_port, &state.preview_connection); } if (status == MMAL_SUCCESS) { VCOS_STATUS_T vcos_status; if (state.filename) { if (state.verbose) printf("Opening output file %s\n", state.filename); output_file = fopen(state.filename, "wb"); if (!output_file) { // Notify user, carry on but discarding encoded output buffers vcos_log_error("%s: Error opening output file: %s\nNo output file will be generated\n", __func__, state.filename); } } // Set up our userdata - this is passed though to the callback where we need the information. callback_data.file_handle = output_file; callback_data.pstate = &state; vcos_status = vcos_semaphore_create(&callback_data.complete_semaphore, "RaspiStill-sem", 0); vcos_assert(vcos_status == VCOS_SUCCESS); camera_still_port->userdata = (struct MMAL_PORT_USERDATA_T *)&callback_data; if (state.verbose) printf("Enabling camera still output port\n"); // Enable the camera still output port and tell it its callback function status = mmal_port_enable(camera_still_port, camera_buffer_callback); if (status != MMAL_SUCCESS) { vcos_log_error("Failed to setup camera output"); goto error; } if (state.verbose) printf("Starting video preview\n"); // Send all the buffers to the encoder output port { int num = mmal_queue_length(state.camera_pool->queue); int q; for (q=0;q<num;q++) { MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(state.camera_pool->queue); if (!buffer) vcos_log_error("Unable to get a required buffer %d from pool queue", q); if (mmal_port_send_buffer(camera_still_port, buffer)!= MMAL_SUCCESS) vcos_log_error("Unable to send a buffer to encoder output port (%d)", q); } } // Now wait until we need to do the capture vcos_sleep(state.timeout); // And only do the capture if we have specified a filename and its opened OK if (output_file) { if (state.verbose) printf("Starting capture\n"); // Fire the capture if (mmal_port_parameter_set_boolean(camera_still_port, MMAL_PARAMETER_CAPTURE, 1) != MMAL_SUCCESS) { vcos_log_error("%s: Failed to start capture", __func__); } else { // Wait for capture to complete // For some reason using vcos_semaphore_wait_timeout sometimes returns immediately with bad parameter error // even though it appears to be all correct, so reverting to untimed one until figure out why its erratic vcos_semaphore_wait(&callback_data.complete_semaphore); if (state.verbose) printf("Finished capture\n"); } } vcos_semaphore_delete(&callback_data.complete_semaphore); } else { mmal_status_to_int(status); vcos_log_error("%s: Failed to connect camera to preview", __func__); } error: mmal_status_to_int(status); if (state.verbose) printf("Closing down\n"); if (output_file) fclose(output_file); // Disable all our ports that are not handled by connections check_disable_port(camera_video_port); if (state.preview_parameters.wantPreview ) mmal_connection_destroy(state.preview_connection); /* Disable components */ if (state.preview_parameters.preview_component) mmal_component_disable(state.preview_parameters.preview_component); if (state.camera_component) mmal_component_disable(state.camera_component); raspipreview_destroy(&state.preview_parameters); destroy_camera_component(&state); if (state.verbose) printf("Close down completed, all components disconnected, disabled and destroyed\n\n"); } return 0; }
/** * main */ int main(int argc, const char **argv) { // Our main data storage vessel.. RASPISTILL_STATE state; MMAL_STATUS_T status = -1; MMAL_PORT_T *camera_preview_port = NULL; MMAL_PORT_T *camera_video_port = NULL; MMAL_PORT_T *camera_still_port = NULL; MMAL_PORT_T *preview_input_port = NULL; MMAL_PORT_T *encoder_input_port = NULL; MMAL_PORT_T *encoder_output_port = NULL; bcm_host_init(); signal(SIGINT, signal_handler); default_status(&state); if (!create_camera_component(&state)) { vcos_log_error("%s: Failed to create camera component", __func__); } //else if (!raspipreview_create(&state.preview_parameters)) //{ // vcos_log_error("%s: Failed to create preview component", __func__); // destroy_camera_component(&state); //} else if (!create_encoder_component(&state)) { vcos_log_error("%s: Failed to create encode component", __func__); raspipreview_destroy(&state.preview_parameters); destroy_camera_component(&state); } else { PORT_USERDATA callback_data; // *** PR : we don't want preview camera_preview_port = NULL;//state.camera_component->output[MMAL_CAMERA_PREVIEW_PORT]; camera_video_port = state.camera_component->output[MMAL_CAMERA_VIDEO_PORT]; camera_still_port = state.camera_component->output[MMAL_CAMERA_CAPTURE_PORT]; preview_input_port = state.preview_parameters.preview_component->input[0]; encoder_input_port = state.encoder_component->input[0]; encoder_output_port = state.encoder_component->output[0]; if (state.preview_parameters.wantPreview ) { if (state.verbose) { fprintf(stderr, "Connecting camera preview port to preview input port\n"); fprintf(stderr, "Starting video preview\n"); } // PR : we don't want preview // Connect camera to preview // status = connect_ports(camera_preview_port, preview_input_port, &state.preview_connection); } VCOS_STATUS_T vcos_status; if (state.verbose) fprintf(stderr, "Connecting camera stills port to encoder input port\n"); // Now connect the camera to the encoder status = connect_ports(camera_still_port, encoder_input_port, &state.encoder_connection); if (status != MMAL_SUCCESS) { vcos_log_error("%s: Failed to connect camera video port to encoder input", __func__); goto error; } // Set up our userdata - this is passed though to the callback where we need the information. // Null until we open our filename callback_data.file_handle = NULL; callback_data.pstate = &state; vcos_status = vcos_semaphore_create(&callback_data.complete_semaphore, "RaspiStill-sem", 0); vcos_assert(vcos_status == VCOS_SUCCESS); encoder_output_port->userdata = (struct MMAL_PORT_USERDATA_T *)&callback_data; if (state.verbose) fprintf(stderr, "Enabling encoder output port\n"); // Enable the encoder output port and tell it its callback function status = mmal_port_enable(encoder_output_port, encoder_buffer_callback); if (status != MMAL_SUCCESS) { vcos_log_error("Failed to setup encoder output"); goto error; } { int num_iterations = state.timelapse ? state.timeout / state.timelapse : 1; int frame; for (frame = 1;frame<=num_iterations; frame++) { if (state.timelapse) vcos_sleep(state.timelapse); else vcos_sleep(state.timeout); // Send all the buffers to the encoder output port int num = mmal_queue_length(state.encoder_pool->queue); int q; for (q=0;q<num;q++) { MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(state.encoder_pool->queue); if (!buffer) vcos_log_error("Unable to get a required buffer %d from pool queue", q); if (mmal_port_send_buffer(encoder_output_port, buffer)!= MMAL_SUCCESS) vcos_log_error("Unable to send a buffer to encoder output port (%d)", q); } if (mmal_port_parameter_set_boolean(camera_still_port, MMAL_PARAMETER_CAPTURE, 1) != MMAL_SUCCESS) { vcos_log_error("%s: Failed to start capture", __func__); } else { // Wait for capture to complete // For some reason using vcos_semaphore_wait_timeout sometimes returns immediately with bad parameter error // even though it appears to be all correct, so reverting to untimed one until figure out why its erratic vcos_semaphore_wait(&callback_data.complete_semaphore); } } // end for (frame) vcos_semaphore_delete(&callback_data.complete_semaphore); } error: mmal_status_to_int(status); // Disable all our ports that are not handled by connections check_disable_port(camera_video_port); check_disable_port(encoder_output_port); // PR : we don't want preview //if (state.preview_parameters.wantPreview ) // mmal_connection_destroy(state.preview_connection); mmal_connection_destroy(state.encoder_connection); /* Disable components */ if (state.encoder_component) mmal_component_disable(state.encoder_component); if (state.preview_parameters.preview_component) mmal_component_disable(state.preview_parameters.preview_component); if (state.camera_component) mmal_component_disable(state.camera_component); destroy_encoder_component(&state); raspipreview_destroy(&state.preview_parameters); destroy_camera_component(&state); if (state.verbose) fprintf(stderr, "Close down completed, all components disconnected, disabled and destroyed\n\n"); } if (status != 0) raspicamcontrol_check_configuration(128); return 0; }
int main(int argc, char **argv) { MMAL_STATUS_T status = MMAL_EINVAL; MMAL_COMPONENT_T *decoder = 0; MMAL_POOL_T *pool_in = 0, *pool_out = 0; unsigned int count; if (argc < 2) { fprintf(stderr, "invalid arguments\n"); return -1; } #ifndef WIN32 // TODO verify that we dont really need to call bcm_host_init bcm_host_init(); #endif vcos_semaphore_create(&context.semaphore, "example", 1); SOURCE_OPEN(argv[1]); /* Create the decoder component. * This specific component exposes 2 ports (1 input and 1 output). Like most components * its expects the format of its input port to be set by the client in order for it to * know what kind of data it will be fed. */ status = mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_DECODER, &decoder); CHECK_STATUS(status, "failed to create decoder"); /* Set format of video decoder input port */ MMAL_ES_FORMAT_T *format_in = decoder->input[0]->format; format_in->type = MMAL_ES_TYPE_VIDEO; format_in->encoding = MMAL_ENCODING_H264; format_in->es->video.width = 1280; format_in->es->video.height = 720; format_in->es->video.frame_rate.num = 30; format_in->es->video.frame_rate.den = 1; format_in->es->video.par.num = 1; format_in->es->video.par.den = 1; /* If the data is known to be framed then the following flag should be set: * format_in->flags |= MMAL_ES_FORMAT_FLAG_FRAMED; */ SOURCE_READ_CODEC_CONFIG_DATA(codec_header_bytes, codec_header_bytes_size); status = mmal_format_extradata_alloc(format_in, codec_header_bytes_size); CHECK_STATUS(status, "failed to allocate extradata"); format_in->extradata_size = codec_header_bytes_size; if (format_in->extradata_size) memcpy(format_in->extradata, codec_header_bytes, format_in->extradata_size); status = mmal_port_format_commit(decoder->input[0]); CHECK_STATUS(status, "failed to commit format"); /* Display the output port format */ MMAL_ES_FORMAT_T *format_out = decoder->output[0]->format; fprintf(stderr, "%s\n", decoder->output[0]->name); fprintf(stderr, " type: %i, fourcc: %4.4s\n", format_out->type, (char *)&format_out->encoding); fprintf(stderr, " bitrate: %i, framed: %i\n", format_out->bitrate, !!(format_out->flags & MMAL_ES_FORMAT_FLAG_FRAMED)); fprintf(stderr, " extra data: %i, %p\n", format_out->extradata_size, format_out->extradata); fprintf(stderr, " width: %i, height: %i, (%i,%i,%i,%i)\n", format_out->es->video.width, format_out->es->video.height, format_out->es->video.crop.x, format_out->es->video.crop.y, format_out->es->video.crop.width, format_out->es->video.crop.height); /* The format of both ports is now set so we can get their buffer requirements and create * our buffer headers. We use the buffer pool API to create these. */ decoder->input[0]->buffer_num = decoder->input[0]->buffer_num_min; decoder->input[0]->buffer_size = decoder->input[0]->buffer_size_min; decoder->output[0]->buffer_num = decoder->output[0]->buffer_num_min; decoder->output[0]->buffer_size = decoder->output[0]->buffer_size_min; pool_in = mmal_pool_create(decoder->input[0]->buffer_num, decoder->input[0]->buffer_size); pool_out = mmal_pool_create(decoder->output[0]->buffer_num, decoder->output[0]->buffer_size); /* Create a queue to store our decoded video frames. The callback we will get when * a frame has been decoded will put the frame into this queue. */ context.queue = mmal_queue_create(); /* Store a reference to our context in each port (will be used during callbacks) */ decoder->input[0]->userdata = (void *)&context; decoder->output[0]->userdata = (void *)&context; /* Enable all the input port and the output port. * The callback specified here is the function which will be called when the buffer header * we sent to the component has been processed. */ status = mmal_port_enable(decoder->input[0], input_callback); CHECK_STATUS(status, "failed to enable input port"); status = mmal_port_enable(decoder->output[0], output_callback); CHECK_STATUS(status, "failed to enable output port"); /* Component won't start processing data until it is enabled. */ status = mmal_component_enable(decoder); CHECK_STATUS(status, "failed to enable component"); /* Start decoding */ fprintf(stderr, "start decoding\n"); /* This is the main processing loop */ for (count = 0; count < 500; count++) { MMAL_BUFFER_HEADER_T *buffer; /* Wait for buffer headers to be available on either of the decoder ports */ vcos_semaphore_wait(&context.semaphore); /* Send data to decode to the input port of the video decoder */ if ((buffer = mmal_queue_get(pool_in->queue)) != NULL) { SOURCE_READ_DATA_INTO_BUFFER(buffer); if (!buffer->length) break; fprintf(stderr, "sending %i bytes\n", (int)buffer->length); status = mmal_port_send_buffer(decoder->input[0], buffer); CHECK_STATUS(status, "failed to send buffer"); } /* Get our decoded frames */ while ((buffer = mmal_queue_get(context.queue)) != NULL) { /* We have a frame, do something with it (why not display it for instance?). * Once we're done with it, we release it. It will automatically go back * to its original pool so it can be reused for a new video frame. */ fprintf(stderr, "decoded frame\n"); mmal_buffer_header_release(buffer); } /* Send empty buffers to the output port of the decoder */ while ((buffer = mmal_queue_get(pool_out->queue)) != NULL) { status = mmal_port_send_buffer(decoder->output[0], buffer); CHECK_STATUS(status, "failed to send buffer"); } } /* Stop decoding */ fprintf(stderr, "stop decoding\n"); /* Stop everything. Not strictly necessary since mmal_component_destroy() * will do that anyway */ mmal_port_disable(decoder->input[0]); mmal_port_disable(decoder->output[0]); mmal_component_disable(decoder); error: /* Cleanup everything */ if (decoder) mmal_component_destroy(decoder); if (pool_in) mmal_pool_destroy(pool_in); if (pool_out) mmal_pool_destroy(pool_out); if (context.queue) mmal_queue_destroy(context.queue); SOURCE_CLOSE(); vcos_semaphore_delete(&context.semaphore); return status == MMAL_SUCCESS ? 0 : -1; }
int CMMALVideo::Decode(uint8_t* pData, int iSize, double dts, double pts) { //if (g_advancedSettings.CanLogComponent(LOGVIDEO)) // CLog::Log(LOGDEBUG, "%s::%s - %-8p %-6d dts:%.3f pts:%.3f dts_queue(%d) ready_queue(%d) busy_queue(%d)", // CLASSNAME, __func__, pData, iSize, dts == DVD_NOPTS_VALUE ? 0.0 : dts*1e-6, pts == DVD_NOPTS_VALUE ? 0.0 : pts*1e-6, m_dts_queue.size(), m_output_ready.size(), m_output_busy); unsigned int demuxer_bytes = 0; uint8_t *demuxer_content = NULL; MMAL_BUFFER_HEADER_T *buffer; MMAL_STATUS_T status; while (buffer = mmal_queue_get(m_dec_output_pool->queue), buffer) Recycle(buffer); // we need to queue then de-queue the demux packet, seems silly but // mmal might not have an input buffer available when we are called // and we must store the demuxer packet and try again later. // try to send any/all demux packets to mmal decoder. unsigned space = mmal_queue_length(m_dec_input_pool->queue) * m_dec_input->buffer_size; if (pData && m_demux_queue.empty() && space >= (unsigned int)iSize) { demuxer_bytes = iSize; demuxer_content = pData; } else if (pData && iSize) { mmal_demux_packet demux_packet; demux_packet.dts = dts; demux_packet.pts = pts; demux_packet.size = iSize; demux_packet.buff = new uint8_t[iSize]; memcpy(demux_packet.buff, pData, iSize); m_demux_queue_length += demux_packet.size; m_demux_queue.push(demux_packet); } uint8_t *buffer_to_free = NULL; while (1) { while (buffer = mmal_queue_get(m_dec_output_pool->queue), buffer) Recycle(buffer); space = mmal_queue_length(m_dec_input_pool->queue) * m_dec_input->buffer_size; if (!demuxer_bytes && !m_demux_queue.empty()) { mmal_demux_packet &demux_packet = m_demux_queue.front(); if (space >= (unsigned int)demux_packet.size) { // need to lock here to retrieve an input buffer and pop the queue m_demux_queue_length -= demux_packet.size; m_demux_queue.pop(); demuxer_bytes = (unsigned int)demux_packet.size; demuxer_content = demux_packet.buff; buffer_to_free = demux_packet.buff; dts = demux_packet.dts; pts = demux_packet.pts; } } if (demuxer_content) { // 500ms timeout buffer = mmal_queue_timedwait(m_dec_input_pool->queue, 500); if (!buffer) { CLog::Log(LOGERROR, "%s::%s - mmal_queue_get failed", CLASSNAME, __func__); return VC_ERROR; } mmal_buffer_header_reset(buffer); buffer->cmd = 0; if (m_startframe && pts == DVD_NOPTS_VALUE) pts = 0; buffer->pts = pts == DVD_NOPTS_VALUE ? MMAL_TIME_UNKNOWN : pts; buffer->dts = dts == DVD_NOPTS_VALUE ? MMAL_TIME_UNKNOWN : dts; buffer->length = demuxer_bytes > buffer->alloc_size ? buffer->alloc_size : demuxer_bytes; buffer->user_data = (void *)m_decode_frame_number; // set a flag so we can identify primary frames from generated frames (deinterlace) buffer->flags = MMAL_BUFFER_HEADER_FLAG_USER0; // Request decode only (maintain ref frames, but don't return a picture) if (m_drop_state) buffer->flags |= MMAL_BUFFER_HEADER_FLAG_DECODEONLY; memcpy(buffer->data, demuxer_content, buffer->length); demuxer_bytes -= buffer->length; demuxer_content += buffer->length; if (demuxer_bytes == 0) buffer->flags |= MMAL_BUFFER_HEADER_FLAG_FRAME_END; if (g_advancedSettings.CanLogComponent(LOGVIDEO)) CLog::Log(LOGDEBUG, "%s::%s - %-8p %-6d/%-6d dts:%.3f pts:%.3f flags:%x dts_queue(%d) ready_queue(%d) busy_queue(%d) demux_queue(%d) space(%d)", CLASSNAME, __func__, buffer, buffer->length, demuxer_bytes, dts == DVD_NOPTS_VALUE ? 0.0 : dts*1e-6, pts == DVD_NOPTS_VALUE ? 0.0 : pts*1e-6, buffer->flags, m_dts_queue.size(), m_output_ready.size(), m_output_busy, m_demux_queue_length, mmal_queue_length(m_dec_input_pool->queue) * m_dec_input->buffer_size); assert((int)buffer->length > 0); status = mmal_port_send_buffer(m_dec_input, buffer); if (status != MMAL_SUCCESS) { CLog::Log(LOGERROR, "%s::%s Failed send buffer to decoder input port (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); return VC_ERROR; } if (demuxer_bytes == 0) { m_decode_frame_number++; m_startframe = true; if (m_drop_state) { m_droppedPics += m_deint ? 2:1; } else { // only push if we are successful with feeding mmal pthread_mutex_lock(&m_output_mutex); m_dts_queue.push(dts); assert(m_dts_queue.size() < 5000); pthread_mutex_unlock(&m_output_mutex); } if (m_changed_count_dec != m_changed_count) { if (g_advancedSettings.CanLogComponent(LOGVIDEO)) CLog::Log(LOGDEBUG, "%s::%s format changed frame:%d(%d)", CLASSNAME, __func__, m_changed_count_dec, m_changed_count); m_changed_count_dec = m_changed_count; if (!change_dec_output_format()) { CLog::Log(LOGERROR, "%s::%s - change_dec_output_format() failed", CLASSNAME, __func__); return VC_ERROR; } } EDEINTERLACEMODE deinterlace_request = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode; EINTERLACEMETHOD interlace_method = g_renderManager.AutoInterlaceMethod(CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod); bool deinterlace = m_interlace_mode != MMAL_InterlaceProgressive; if (deinterlace_request == VS_DEINTERLACEMODE_OFF) deinterlace = false; else if (deinterlace_request == VS_DEINTERLACEMODE_FORCE) deinterlace = true; if (((deinterlace && interlace_method != m_interlace_method) || !deinterlace) && m_deint) DestroyDeinterlace(); if (deinterlace && !m_deint) CreateDeinterlace(interlace_method); if (buffer_to_free) { delete [] buffer_to_free; buffer_to_free = NULL; demuxer_content = NULL; continue; } while (buffer = mmal_queue_get(m_dec_output_pool->queue), buffer) Recycle(buffer); } } if (!demuxer_bytes) break; } int ret = 0; if (!m_output_ready.empty()) { if (g_advancedSettings.CanLogComponent(LOGVIDEO)) CLog::Log(LOGDEBUG, "%s::%s - got space for output: demux_queue(%d) space(%d)", CLASSNAME, __func__, m_demux_queue_length, mmal_queue_length(m_dec_input_pool->queue) * m_dec_input->buffer_size); ret |= VC_PICTURE; } if (mmal_queue_length(m_dec_input_pool->queue) > 0 && !m_demux_queue_length) { if (g_advancedSettings.CanLogComponent(LOGVIDEO)) CLog::Log(LOGDEBUG, "%s::%s - got output picture:%d", CLASSNAME, __func__, m_output_ready.size()); ret |= VC_BUFFER; } if (!ret) { if (g_advancedSettings.CanLogComponent(LOGVIDEO)) CLog::Log(LOGDEBUG, "%s::%s - Nothing to do: dts_queue(%d) ready_queue(%d) busy_queue(%d) demux_queue(%d) space(%d)", CLASSNAME, __func__, m_dts_queue.size(), m_output_ready.size(), m_output_busy, m_demux_queue_length, mmal_queue_length(m_dec_input_pool->queue) * m_dec_input->buffer_size); Sleep(10); // otherwise we busy spin } return ret; }
/** * main */ int main(int argc, const char **argv) { // Our main data storage vessel.. RASPISTILLYUV_STATE state; int exit_code = EX_OK; MMAL_STATUS_T status = MMAL_SUCCESS; MMAL_PORT_T *camera_preview_port = NULL; MMAL_PORT_T *camera_video_port = NULL; MMAL_PORT_T *camera_still_port = NULL; MMAL_PORT_T *preview_input_port = NULL; FILE *output_file = NULL; bcm_host_init(); // Register our application with the logging system vcos_log_register("RaspiStill", VCOS_LOG_CATEGORY); signal(SIGINT, signal_handler); // Disable USR1 for the moment - may be reenabled if go in to signal capture mode signal(SIGUSR1, SIG_IGN); default_status(&state); // Do we have any parameters if (argc == 1) { fprintf(stdout, "\n%s Camera App %s\n\n", basename(argv[0]), VERSION_STRING); display_valid_parameters(basename(argv[0])); exit(EX_USAGE); } default_status(&state); // Parse the command line and put options in to our status structure if (parse_cmdline(argc, argv, &state)) { status = -1; exit(EX_USAGE); } if (state.verbose) { fprintf(stderr, "\n%s Camera App %s\n\n", basename(argv[0]), VERSION_STRING); dump_status(&state); } // OK, we have a nice set of parameters. Now set up our components // We have two components. Camera and Preview // Camera is different in stills/video, but preview // is the same so handed off to a separate module if ((status = create_camera_component(&state)) != MMAL_SUCCESS) { vcos_log_error("%s: Failed to create camera component", __func__); exit_code = EX_SOFTWARE; } else if ((status = raspipreview_create(&state.preview_parameters)) != MMAL_SUCCESS) { vcos_log_error("%s: Failed to create preview component", __func__); destroy_camera_component(&state); exit_code = EX_SOFTWARE; } else { PORT_USERDATA callback_data; if (state.verbose) fprintf(stderr, "Starting component connection stage\n"); camera_preview_port = state.camera_component->output[MMAL_CAMERA_PREVIEW_PORT]; camera_video_port = state.camera_component->output[MMAL_CAMERA_VIDEO_PORT]; camera_still_port = state.camera_component->output[MMAL_CAMERA_CAPTURE_PORT]; // Note we are lucky that the preview and null sink components use the same input port // so we can simple do this without conditionals preview_input_port = state.preview_parameters.preview_component->input[0]; // Connect camera to preview (which might be a null_sink if no preview required) status = connect_ports(camera_preview_port, preview_input_port, &state.preview_connection); if (status == MMAL_SUCCESS) { VCOS_STATUS_T vcos_status; // Set up our userdata - this is passed though to the callback where we need the information. // Null until we open our filename callback_data.file_handle = NULL; callback_data.pstate = &state; vcos_status = vcos_semaphore_create(&callback_data.complete_semaphore, "RaspiStill-sem", 0); vcos_assert(vcos_status == VCOS_SUCCESS); camera_still_port->userdata = (struct MMAL_PORT_USERDATA_T *)&callback_data; if (state.verbose) fprintf(stderr, "Enabling camera still output port\n"); // Enable the camera still output port and tell it its callback function status = mmal_port_enable(camera_still_port, camera_buffer_callback); if (status != MMAL_SUCCESS) { vcos_log_error("Failed to setup camera output"); goto error; } if (state.verbose) fprintf(stderr, "Starting video preview\n"); int frame, keep_looping = 1; FILE *output_file = NULL; char *use_filename = NULL; // Temporary filename while image being written char *final_filename = NULL; // Name that file gets once writing complete frame = 0; while (keep_looping) { keep_looping = wait_for_next_frame(&state, &frame); // Open the file if (state.filename) { if (state.filename[0] == '-') { output_file = stdout; // Ensure we don't upset the output stream with diagnostics/info state.verbose = 0; } else { vcos_assert(use_filename == NULL && final_filename == NULL); status = create_filenames(&final_filename, &use_filename, state.filename, frame); if (status != MMAL_SUCCESS) { vcos_log_error("Unable to create filenames"); goto error; } if (state.verbose) fprintf(stderr, "Opening output file %s\n", final_filename); // Technically it is opening the temp~ filename which will be ranamed to the final filename output_file = fopen(use_filename, "wb"); if (!output_file) { // Notify user, carry on but discarding encoded output buffers vcos_log_error("%s: Error opening output file: %s\nNo output file will be generated\n", __func__, use_filename); } } callback_data.file_handle = output_file; } if (output_file) { int num, q; // There is a possibility that shutter needs to be set each loop. if (mmal_status_to_int(mmal_port_parameter_set_uint32(state.camera_component->control, MMAL_PARAMETER_SHUTTER_SPEED, state.camera_parameters.shutter_speed) != MMAL_SUCCESS)) vcos_log_error("Unable to set shutter speed"); // Send all the buffers to the camera output port num = mmal_queue_length(state.camera_pool->queue); for (q=0;q<num;q++) { MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(state.camera_pool->queue); if (!buffer) vcos_log_error("Unable to get a required buffer %d from pool queue", q); if (mmal_port_send_buffer(camera_still_port, buffer)!= MMAL_SUCCESS) vcos_log_error("Unable to send a buffer to camera output port (%d)", q); } if (state.burstCaptureMode && frame==1) { mmal_port_parameter_set_boolean(state.camera_component->control, MMAL_PARAMETER_CAMERA_BURST_CAPTURE, 1); } if (state.verbose) fprintf(stderr, "Starting capture %d\n", frame); if (mmal_port_parameter_set_boolean(camera_still_port, MMAL_PARAMETER_CAPTURE, 1) != MMAL_SUCCESS) { vcos_log_error("%s: Failed to start capture", __func__); } else { // Wait for capture to complete // For some reason using vcos_semaphore_wait_timeout sometimes returns immediately with bad parameter error // even though it appears to be all correct, so reverting to untimed one until figure out why its erratic vcos_semaphore_wait(&callback_data.complete_semaphore); if (state.verbose) fprintf(stderr, "Finished capture %d\n", frame); } // Ensure we don't die if get callback with no open file callback_data.file_handle = NULL; if (output_file != stdout) { rename_file(&state, output_file, final_filename, use_filename, frame); } } if (use_filename) { free(use_filename); use_filename = NULL; } if (final_filename) { free(final_filename); final_filename = NULL; } } // end for (frame) vcos_semaphore_delete(&callback_data.complete_semaphore); } else { mmal_status_to_int(status); vcos_log_error("%s: Failed to connect camera to preview", __func__); } error: mmal_status_to_int(status); if (state.verbose) fprintf(stderr, "Closing down\n"); if (output_file) fclose(output_file); // Disable all our ports that are not handled by connections check_disable_port(camera_video_port); if (state.preview_connection) mmal_connection_destroy(state.preview_connection); /* Disable components */ if (state.preview_parameters.preview_component) mmal_component_disable(state.preview_parameters.preview_component); if (state.camera_component) mmal_component_disable(state.camera_component); raspipreview_destroy(&state.preview_parameters); destroy_camera_component(&state); if (state.verbose) fprintf(stderr, "Close down completed, all components disconnected, disabled and destroyed\n\n"); } if (status != MMAL_SUCCESS) raspicamcontrol_check_configuration(128); return exit_code; }
/** Start playback on an instance of mmalplay. * Note: this is test code. Do not use it in your app. It *will* change or even be removed without notice. */ MMAL_STATUS_T mmalplay_play(MMALPLAY_T *ctx) { MMAL_STATUS_T status = MMAL_SUCCESS; unsigned int i; LOG_TRACE("%p, %s", ctx, ctx->uri); ctx->time_playback = vcos_getmicrosecs(); /* Start the clocks */ if (ctx->video_clock) mmal_port_parameter_set_boolean(ctx->video_clock, MMAL_PARAMETER_CLOCK_ACTIVE, MMAL_TRUE); if (ctx->audio_clock) mmal_port_parameter_set_boolean(ctx->audio_clock, MMAL_PARAMETER_CLOCK_ACTIVE, MMAL_TRUE); while(1) { MMAL_BUFFER_HEADER_T *buffer; vcos_semaphore_wait(&ctx->event); if (ctx->stop || ctx->status != MMAL_SUCCESS) { status = ctx->status; break; } /* Loop through all the connections */ for (i = 0; i < ctx->connection_num; i++) { MMAL_CONNECTION_T *connection = ctx->connection[i]; if (connection->flags & MMAL_CONNECTION_FLAG_TUNNELLING) continue; /* Nothing else to do in tunnelling mode */ /* Send any queued buffer to the next component */ buffer = mmal_queue_get(connection->queue); while (buffer) { if (buffer->cmd) { status = mmalplay_event_handle(connection, connection->out, buffer); if (status != MMAL_SUCCESS) goto error; buffer = mmal_queue_get(connection->queue); continue; } /* Code specific to handling of the video output port */ if (connection->out == ctx->video_out_port) { if (buffer->length) ctx->decoded_frames++; if (ctx->options.stepping) getchar(); } status = mmal_port_send_buffer(connection->in, buffer); if (status != MMAL_SUCCESS) { LOG_ERROR("mmal_port_send_buffer failed (%i)", status); mmal_queue_put_back(connection->queue, buffer); goto error; } buffer = mmal_queue_get(connection->queue); } /* Send empty buffers to the output port of the connection */ buffer = connection->pool ? mmal_queue_get(connection->pool->queue) : NULL; while (buffer) { status = mmal_port_send_buffer(connection->out, buffer); if (status != MMAL_SUCCESS) { LOG_ERROR("mmal_port_send_buffer failed (%i)", status); mmal_queue_put_back(connection->pool->queue, buffer); goto error; } buffer = mmal_queue_get(connection->pool->queue); } } } error: ctx->time_playback = vcos_getmicrosecs() - ctx->time_playback; /* For still images we want to pause a bit once they are displayed */ if (ctx->is_still_image && status == MMAL_SUCCESS) vcos_sleep(MMALPLAY_STILL_IMAGE_PAUSE); return status; }
// Fetch a decoded buffer and place it into the frame parameter. static int ffmmal_read_frame(AVCodecContext *avctx, AVFrame *frame, int *got_frame) { MMALDecodeContext *ctx = avctx->priv_data; MMAL_BUFFER_HEADER_T *buffer = NULL; MMAL_STATUS_T status = 0; int ret = 0; if (ctx->eos_received) goto done; while (1) { // To ensure decoding in lockstep with a constant delay between fed packets // and output frames, we always wait until an output buffer is available. // Except during start we don't know after how many input packets the decoder // is going to return the first buffer, and we can't distinguish decoder // being busy from decoder waiting for input. So just poll at the start and // keep feeding new data to the buffer. // We are pretty sure the decoder will produce output if we sent more input // frames than what a H.264 decoder could logically delay. This avoids too // excessive buffering. // We also wait if we sent eos, but didn't receive it yet (think of decoding // stream with a very low number of frames). if (avpriv_atomic_int_get(&ctx->packets_buffered) > MAX_DELAYED_FRAMES || (ctx->packets_sent && ctx->eos_sent)) { // MMAL will ignore broken input packets, which means the frame we // expect here may never arrive. Dealing with this correctly is // complicated, so here's a hack to avoid that it freezes forever // in this unlikely situation. buffer = mmal_queue_timedwait(ctx->queue_decoded_frames, 100); if (!buffer) { av_log(avctx, AV_LOG_ERROR, "Did not get output frame from MMAL.\n"); ret = AVERROR_UNKNOWN; goto done; } } else { buffer = mmal_queue_get(ctx->queue_decoded_frames); if (!buffer) goto done; } ctx->eos_received |= !!(buffer->flags & MMAL_BUFFER_HEADER_FLAG_EOS); if (ctx->eos_received) goto done; if (buffer->cmd == MMAL_EVENT_FORMAT_CHANGED) { MMAL_COMPONENT_T *decoder = ctx->decoder; MMAL_EVENT_FORMAT_CHANGED_T *ev = mmal_event_format_changed_get(buffer); MMAL_BUFFER_HEADER_T *stale_buffer; av_log(avctx, AV_LOG_INFO, "Changing output format.\n"); if ((status = mmal_port_disable(decoder->output[0]))) goto done; while ((stale_buffer = mmal_queue_get(ctx->queue_decoded_frames))) mmal_buffer_header_release(stale_buffer); mmal_format_copy(decoder->output[0]->format, ev->format); if ((ret = ffmal_update_format(avctx)) < 0) goto done; if ((status = mmal_port_enable(decoder->output[0], output_callback))) goto done; if ((ret = ffmmal_fill_output_port(avctx)) < 0) goto done; if ((ret = ffmmal_fill_input_port(avctx)) < 0) goto done; mmal_buffer_header_release(buffer); continue; } else if (buffer->cmd) { char s[20]; av_get_codec_tag_string(s, sizeof(s), buffer->cmd); av_log(avctx, AV_LOG_WARNING, "Unknown MMAL event %s on output port\n", s); goto done; } else if (buffer->length == 0) { // Unused output buffer that got drained after format change. mmal_buffer_header_release(buffer); continue; } ctx->frames_output++; if ((ret = ffmal_copy_frame(avctx, frame, buffer)) < 0) goto done; *got_frame = 1; break; } done: if (buffer) mmal_buffer_header_release(buffer); if (status && ret >= 0) ret = AVERROR_UNKNOWN; return ret; }
static int send_output_buffer(decoder_t *dec) { decoder_sys_t *sys = dec->p_sys; MMAL_BUFFER_HEADER_T *buffer; picture_sys_t *p_sys; picture_t *picture; MMAL_STATUS_T status; unsigned buffer_size = 0; int ret = 0; if (!sys->output->is_enabled) return VLC_EGENERIC; /* If local output pool is allocated, use it - this is only the case for * non-opaque modes */ if (sys->output_pool) { buffer = mmal_queue_get(sys->output_pool->queue); if (!buffer) { msg_Warn(dec, "Failed to get new buffer"); return VLC_EGENERIC; } } picture = decoder_NewPicture(dec); if (!picture) { msg_Warn(dec, "Failed to get new picture"); ret = -1; goto err; } p_sys = picture->p_sys; for (int i = 0; i < picture->i_planes; i++) buffer_size += picture->p[i].i_lines * picture->p[i].i_pitch; if (sys->output_pool) { mmal_buffer_header_reset(buffer); buffer->user_data = picture; buffer->alloc_size = sys->output->buffer_size; if (buffer_size < sys->output->buffer_size) { msg_Err(dec, "Retrieved picture with too small data block (%d < %d)", buffer_size, sys->output->buffer_size); ret = VLC_EGENERIC; goto err; } if (!sys->opaque) buffer->data = picture->p[0].p_pixels; } else { buffer = p_sys->buffer; if (!buffer) { msg_Warn(dec, "Picture has no buffer attached"); picture_Release(picture); return VLC_EGENERIC; } buffer->data = p_sys->buffer->data; } buffer->cmd = 0; status = mmal_port_send_buffer(sys->output, buffer); if (status != MMAL_SUCCESS) { msg_Err(dec, "Failed to send buffer to output port (status=%"PRIx32" %s)", status, mmal_status_to_string(status)); ret = -1; goto err; } atomic_fetch_add(&sys->output_in_transit, 1); return ret; err: if (picture) picture_Release(picture); if (sys->output_pool && buffer) { buffer->data = NULL; mmal_buffer_header_release(buffer); } return ret; }