static void on_request_completed() { assert(d7asp_state == D7ASP_STATE_MASTER); if(!bitmap_get(current_master_session.progress_bitmap, current_request_id)) { current_request_retry_count++; // the request may be retransmitted, don't free yet (this will be done in flush_fifo() when failed) } else { // request completed, no retries needed so we can free the packet packet_queue_free_packet(current_request_packet); // terminate the dialog if all request handled // we need to switch to the state idle otherwise we may receive a new packet before the task flush_fifos is handled // in this case, we may assert since the state remains MASTER if (current_request_id == current_master_session.next_request_id - 1) { flush_completed(); return; } current_request_id = NO_ACTIVE_REQUEST_ID; } sched_post_task(&flush_fifos); // continue flushing until all request handled ... }
static void write_audio_frame(AVFormatContext *oc, AVStream *st, struct transcoder_ctx_t *ctx) { AVPacket pkt = {0}; // data and size must be 0; struct packet_t *source_audio; av_init_packet(&pkt); if (!(source_audio = packet_queue_get_next_item_asynch(ctx->processed_audio_queue))) { return; } pkt.stream_index = st->index; pkt.size = source_audio->data_length; pkt.data = source_audio->data; pkt.pts = av_rescale_q(source_audio->PTS, ctx->input_context->streams[ctx->audio_stream_index]->time_base, st->time_base); pkt.dts = av_rescale_q(source_audio->DTS, ctx->input_context->streams[ctx->audio_stream_index]->time_base, st->time_base); pkt.duration = source_audio->duration; pkt.destruct = avpacket_destruct; /* Write the compressed frame to the media file. */ if (av_interleaved_write_frame(oc, &pkt) != 0) { fprintf(stderr, "[DEBUG] Error while writing audio frame\n"); } packet_queue_free_packet(source_audio, 0); }
void d7asp_signal_packet_csma_ca_insertion_completed(bool succeeded) { if(d7asp_state == D7ASP_STATE_MASTER) { if(!succeeded) { on_request_completed(); return; } // for the lowest QoS level the packet is ack-ed when CSMA/CA process succeeded if(current_master_session.config.qos.qos_resp_mode == SESSION_RESP_MODE_NO) { mark_current_request_done(); bitmap_set(current_master_session.success_bitmap, current_request_id); // As we don't wait a response, the request can be completed on_request_completed(); } } else if ((!succeeded) && ((d7asp_state == D7ASP_STATE_SLAVE) || (d7asp_state == D7ASP_STATE_SLAVE_PENDING_MASTER))) { packet_queue_free_packet(current_response_packet); current_response_packet = NULL; } }
void packet_disassemble(packet_t* packet) { DPRINT_DATA_DLL(packet->hw_radio_packet.data, packet->hw_radio_packet.length + 1); // TODO tmp if (packet->hw_radio_packet.rx_meta.crc_status == HW_CRC_UNAVAILABLE) { uint16_t crc = __builtin_bswap16(crc_calculate(packet->hw_radio_packet.data, packet->hw_radio_packet.length + 1 - 2)); if(memcmp(&crc, packet->hw_radio_packet.data + packet->hw_radio_packet.length + 1 - 2, 2) != 0) { DPRINT_DLL("CRC invalid"); DPRINT_DATA_DLL(&crc, 2); goto cleanup; } } else if (packet->hw_radio_packet.rx_meta.crc_status == HW_CRC_INVALID) { DPRINT_DLL("CRC invalid"); goto cleanup; } uint8_t data_idx = 1; if(!dll_disassemble_packet_header(packet, &data_idx)) goto cleanup; // TODO assuming D7ANP for now if(!d7anp_disassemble_packet_header(packet, &data_idx)) goto cleanup; if(!d7atp_disassemble_packet_header(packet, &data_idx)) goto cleanup; // TODO footers // extract payload packet->payload_length = packet->hw_radio_packet.length + 1 - data_idx - 2; // exclude the headers CRC bytes // TODO exclude footers memcpy(packet->payload, packet->hw_radio_packet.data + data_idx, packet->payload_length); DPRINT_FWK("Done disassembling packet"); d7atp_process_received_packet(packet); return; cleanup: DPRINT_FWK("Skipping packet"); packet_queue_free_packet(packet); return; }
void packet_disassemble(packet_t* packet) { log_print_data(packet->hw_radio_packet.data, packet->hw_radio_packet.length + 1); // TODO tmp uint16_t crc = __builtin_bswap16(crc_calculate(packet->hw_radio_packet.data, packet->hw_radio_packet.length - 2)); if(memcmp(&crc, packet->hw_radio_packet.data + packet->hw_radio_packet.length + 1 - 2, 2) != 0) { DPRINT(LOG_STACK_DLL, "CRC invalid"); goto cleanup; } uint8_t data_idx = 1; if(!dll_disassemble_packet_header(packet, &data_idx)) { DPRINT(LOG_STACK_DLL, "disassemble header failed"); goto cleanup; } // TODO assuming D7ANP for now if(!d7anp_disassemble_packet_header(packet, &data_idx)) { DPRINT(LOG_STACK_NWL, "disassemble header failed"); goto cleanup; } if(!d7atp_disassemble_packet_header(packet, &data_idx)) { DPRINT(LOG_STACK_TRANS, "disassemble header failed"); goto cleanup; } // TODO footers // extract payload packet->payload_length = packet->hw_radio_packet.length + 1 - data_idx - 2; // exclude the headers CRC bytes // TODO exclude footers memcpy(packet->payload, packet->hw_radio_packet.data + data_idx, packet->payload_length); DPRINT(LOG_STACK_FWK, "Done disassembling packet"); d7atp_process_received_packet(packet); return; cleanup: DPRINT(LOG_STACK_FWK, "Skipping packet"); packet_queue_free_packet(packet); return; }
void d7asp_signal_packet_transmitted(packet_t *packet) { DPRINT("Packet transmitted"); // if Tc is not provided, the signal transaction_response_period_elapsed is not expected if ((d7asp_state == D7ASP_STATE_MASTER) && (!packet->d7atp_ctrl.ctrl_tc)) on_request_completed(); else if(d7asp_state == D7ASP_STATE_SLAVE || d7asp_state == D7ASP_STATE_SLAVE_PENDING_MASTER) { assert(current_response_packet == packet); // when in slave session we can immediately cleanup the transmitted response. // requests (in master sessions) will be cleanup upon termination of the dialog. current_response_packet = NULL; packet_queue_free_packet(packet); } }
void d7asp_signal_transaction_response_period_elapsed() { if(d7asp_state == D7ASP_STATE_MASTER) on_request_completed(); else if((d7asp_state == D7ASP_STATE_SLAVE) || (d7asp_state == D7ASP_STATE_SLAVE_PENDING_MASTER)) { if (current_response_packet) { DPRINT("Discard the response since the response period is expired"); packet_queue_free_packet(current_response_packet); current_response_packet = NULL; } if (d7asp_state == D7ASP_STATE_SLAVE) switch_state(D7ASP_STATE_IDLE); else if(d7asp_state == D7ASP_STATE_SLAVE_PENDING_MASTER) { switch_state(D7ASP_STATE_MASTER); DPRINT("Schedule task to flush the fifo"); sched_post_task(&flush_fifos); } } }
void *writer_thread(void *thread_ctx) { struct transcoder_ctx_t *ctx = (struct transcoder_ctx_t *) thread_ctx; AVStream *video_stream = NULL, *audio_stream = NULL; AVFormatContext *output_context = init_output_context(ctx, &video_stream, &audio_stream); struct mux_state_t mux_state = {0}; //from omxtx mux_state.pts_offset = av_rescale_q(ctx->input_context->start_time, AV_TIME_BASE_Q, output_context->streams[ctx->video_stream_index]->time_base); #if 0 FILE *out_file; out_file = fopen(ctx->output_filename, "wb"); if (out_file == NULL) { printf("error creating output file. DYING \n"); exit(1); } #endif //write stream header if any avformat_write_header(output_context, NULL); //do not start doing anything until we get an encoded packet pthread_mutex_lock(&ctx->pipeline.video_encode.is_running_mutex); while (!ctx->pipeline.video_encode.is_running) { pthread_cond_wait(&ctx->pipeline.video_encode.is_running_cv, &ctx->pipeline.video_encode.is_running_mutex); } while (!ctx->pipeline.video_encode.eos || !ctx->processed_audio_queue->queue_finished) { //FIXME a memory barrier is required here so that we don't race //on above variables //fill a buffer with video data OERR(OMX_FillThisBuffer(ctx->pipeline.video_encode.h, omx_get_next_output_buffer(&ctx->pipeline.video_encode))); write_audio_frame(output_context, audio_stream, ctx); //write full audio frame //FIXME no guarantee that we have a full frame per packet? write_video_frame(output_context, video_stream, ctx, &mux_state); //write full video frame //encoded_video_queue is being filled by the previous command #if 0 struct packet_t *encoded_packet = packet_queue_get_next_item(&ctx->pipeline.encoded_video_queue); fwrite(encoded_packet->data, 1, encoded_packet->data_length, out_file); packet_queue_free_packet(encoded_packet, 1); #endif } av_write_trailer(output_context); //free all the resources avcodec_close(video_stream->codec); avcodec_close(audio_stream->codec); /* Free the streams. */ for (int i = 0; i < output_context->nb_streams; i++) { av_freep(&output_context->streams[i]->codec); av_freep(&output_context->streams[i]); } if (!(output_context->oformat->flags & AVFMT_NOFILE)) { /* Close the output file. */ avio_close(output_context->pb); } /* free the stream */ av_free(output_context); free(mux_state.pps); free(mux_state.sps); #if 0 fclose(out_file); #endif }
static void write_video_frame(AVFormatContext *oc, AVStream *st, struct transcoder_ctx_t *ctx, struct mux_state_t *mux_state) { AVPacket pkt = { 0 }; // data and size must be 0; struct packet_t *source_video; //write video frame after we have init'ed the pps/sps packets mux_state->flush_framebuf = (mux_state->pps && mux_state->sps); //TODO Put encoded_video_queue into the main ctx if(!(source_video = packet_queue_get_next_item_asynch(&ctx->pipeline.encoded_video_queue))) { return; } if (!(source_video->flags & OMX_BUFFERFLAG_ENDOFNAL)) { //We don't have full NAL - buffer until we do fprintf(stderr, "[DEBUG] We got a partial NAL - buffering\n"); if (!mux_state->buf) { mux_state->buf = malloc(_1mb); } memcpy(&mux_state->buf[mux_state->buf_offset], source_video->data, source_video->data_length); mux_state->buf_offset += source_video->data_length; free(source_video->data); //in this case we have to free it } else { //we got full NAL - write it fprintf(stderr, "[DEBUG] We got the end of a NAL - writing\n"); av_init_packet(&pkt); if (mux_state->buf_offset) { //if we have buffered data, write the //end of the NAL and set appropriate bufs //out of bounds check? memcpy(&mux_state->buf[mux_state->buf_offset], source_video->data, source_video->data_length); mux_state->buf_offset += source_video->data_length; pkt.data = mux_state->buf; pkt.size = mux_state->buf_offset; mux_state->buf_offset = 0; mux_state->buf = NULL; } else { fprintf(stderr, "[DEBUG] We got a full NAL - writing\n"); //we get a full nal in current packet so write it directly. pkt.data = source_video->data; pkt.size = source_video->data_length; } pkt.stream_index = st->index; if (source_video->flags & OMX_BUFFERFLAG_SYNCFRAME) { pkt.flags |= AV_PKT_FLAG_KEY; } pkt.pts = av_rescale_q(source_video->PTS, ctx->omx_timebase, oc->streams[st->index]->time_base); // if(pkt.pts) { pkt.pts -= mux_state->pts_offset; } pkt.dts = AV_NOPTS_VALUE; pkt.destruct = avpacket_destruct; //check for SPS/PPS packets and deal with them if(extract_pps_ssp_packet(mux_state, &pkt)) { init_stream_extra_data(oc, mux_state, ctx->video_stream_index); } } /* Write the compressed frame to the media file. */ if (mux_state->flush_framebuf) { int r; // fprintf(stderr, "Writing video frame\n"); if (r = av_interleaved_write_frame(oc, &pkt)) { if (r != 0) { char err[256]; av_strerror(r, err, sizeof (err)); fprintf(stderr, "[DEBUG] Error while writing video frame : %s\n", err); } } } packet_queue_free_packet(source_video, 0); }
// TODO we assume a fifo contains only ALP commands, but according to spec this can be any kind of "Request" // we will see later what this means. For instance how to add a request which starts D7AAdvP etc d7asp_queue_result_t d7asp_queue_alp_actions(d7asp_master_session_t* session, uint8_t* alp_payload_buffer, uint8_t alp_payload_length) { DPRINT("Queuing ALP actions"); // TODO can be called in all session states? assert(session == ¤t_master_session); // TODO tmp assert(session->request_buffer_tail_idx + alp_payload_length < MODULE_D7AP_FIFO_COMMAND_BUFFER_SIZE); assert(session->next_request_id < MODULE_D7AP_FIFO_MAX_REQUESTS_COUNT); // TODO do not assert but let upper layer handle this single_request_retry_limit = 3; // TODO read from SEL config file // add request to buffer // TODO request can contain 1 or more ALP commands, find a way to group commands in requests instead of dumping all requests in one buffer uint8_t request_id = session->next_request_id; session->requests_indices[request_id] = session->request_buffer_tail_idx; session->requests_lengths[request_id] = alp_payload_length; memcpy(session->request_buffer + session->request_buffer_tail_idx, alp_payload_buffer, alp_payload_length); session->request_buffer_tail_idx += alp_payload_length + 1; session->next_request_id++; // TODO for master only set to pending when asked by upper layer (ie new function call) if(d7asp_state == D7ASP_STATE_IDLE) switch_state(D7ASP_STATE_MASTER); else if(d7asp_state == D7ASP_STATE_SLAVE) switch_state(D7ASP_STATE_SLAVE_PENDING_MASTER); return (d7asp_queue_result_t){ .fifo_token = session->token, .request_id = request_id }; } bool d7asp_process_received_packet(packet_t* packet, bool extension) { hw_watchdog_feed(); // TODO do here? d7asp_result_t result = { .channel = packet->hw_radio_packet.rx_meta.rx_cfg.channel_id, .rx_level = - packet->hw_radio_packet.rx_meta.rssi, .link_budget = (packet->dll_header.control_eirp_index + 32) - packet->hw_radio_packet.rx_meta.rssi, .target_rx_level = 80, // TODO not implemented yet, use default for now .status = { .ucast = 0, // TODO .nls = packet->d7anp_ctrl.origin_addressee_ctrl_nls_enabled, .retry = false, // TODO .missed = false, // TODO }, .response_to = packet->d7atp_tc, .addressee = packet->d7anp_addressee // .fifo_token and .seqnr filled below }; if(d7asp_state == D7ASP_STATE_MASTER) { assert(packet->d7atp_dialog_id == current_master_session.token); assert(packet->d7atp_transaction_id == current_request_id); // received ack DPRINT("Received ACK"); if(current_master_session.config.qos.qos_resp_mode != SESSION_RESP_MODE_NO && current_master_session.config.qos.qos_resp_mode != SESSION_RESP_MODE_NO_RPT) { // for SESSION_RESP_MODE_NO and SESSION_RESP_MODE_NO_RPT the request was already marked as done // upon successfull CSMA insertion. We don't care about response in these cases. result.fifo_token = current_master_session.token; result.seqnr = current_request_id; bitmap_set(current_master_session.success_bitmap, current_request_id); mark_current_request_done(); assert(packet != current_request_packet); } alp_d7asp_request_completed(result, packet->payload, packet->payload_length); // if(d7asp_init_args != NULL && d7asp_init_args->d7asp_fifo_request_completed_cb != NULL) // d7asp_init_args->d7asp_fifo_request_completed_cb(result, packet->payload, packet->payload_length); // TODO ALP should notify app if needed, refactor packet_queue_free_packet(packet); // ACK can be cleaned // switch to the state slave when the D7ATP Dialog Extension Procedure is initiated and all request are handled if ((extension) && (current_request_id == current_master_session.next_request_id - 1)) { DPRINT("Dialog Extension Procedure is initiated, mark the FIFO flush" " completed before switching to a responder state"); alp_d7asp_fifo_flush_completed(current_master_session.token, current_master_session.progress_bitmap, current_master_session.success_bitmap, REQUESTS_BITMAP_BYTE_COUNT); current_master_session.state = D7ASP_MASTER_SESSION_IDLE; d7atp_signal_dialog_termination(); switch_state(D7ASP_STATE_SLAVE); } return true; } else if(d7asp_state == D7ASP_STATE_IDLE || d7asp_state == D7ASP_STATE_SLAVE) { // received a request, start slave session, process and respond if(d7asp_state == D7ASP_STATE_IDLE) switch_state(D7ASP_STATE_SLAVE); // don't switch when already in slave state result.fifo_token = packet->d7atp_dialog_id; result.seqnr = packet->d7atp_transaction_id; // TODO move to ALP if(packet->payload_length > 0) { if(alp_get_operation(packet->payload) == ALP_OP_RETURN_FILE_DATA) { // received unsollicited data, notify appl DPRINT("Received unsollicited data"); if(d7asp_init_args != NULL && d7asp_init_args->d7asp_received_unsollicited_data_cb != NULL) d7asp_init_args->d7asp_received_unsollicited_data_cb(result, packet->payload, packet->payload_length); packet->payload_length = 0; // no response payload } else { // build response, we will reuse the same packet for this // we will first try to process the command against the local FS // if the FS handler cannot process this, and a status response is requested, a status operand will be present in the response payload bool handled = alp_process_command(packet->payload, packet->payload_length, packet->payload, &packet->payload_length, ALP_CMD_ORIGIN_D7ASP); // ... and if not handled we'll give the application a chance to handle this by returning an ALP response. // if the application fails to handle the request as well the ALP status operand supplied by alp_process_command_fs_itf() will be transmitted (if requested) if(!handled) { DPRINT("ALP command could not be processed by local FS"); if(d7asp_init_args != NULL && d7asp_init_args->d7asp_received_unhandled_alp_command_cb != NULL) { DPRINT("ALP command passed to application for processing"); d7asp_init_args->d7asp_received_unhandled_alp_command_cb(packet->payload, packet->payload_length, packet->payload, &packet->payload_length); } } } } // TODO notify upper layer? // execute slave transaction if(packet->payload_length == 0 && !packet->d7atp_ctrl.ctrl_is_ack_requested) goto discard_request; // no need to respond, clean up DPRINT("Sending response"); current_response_packet = packet; /* * activate the dialog extension procedure in the unicast response if the dialog is terminated * and a master session is pending */ if((packet->dll_header.control_target_address_set) && (packet->d7atp_ctrl.ctrl_is_stop) && (d7asp_state == D7ASP_STATE_SLAVE_PENDING_MASTER)) { packet->d7atp_ctrl.ctrl_is_start = true; // TODO set packet->d7anp_listen_timeout according the time remaining in the current transaction // + the maximum time to send the first request of the pending session. } else packet->d7atp_ctrl.ctrl_is_start = 0; d7atp_respond_dialog(packet); return true; } else assert(false); discard_request: packet_queue_free_packet(packet); return false; }
static void flush_fifos() { assert(d7asp_state == D7ASP_STATE_MASTER); DPRINT("Flushing FIFOs"); hw_watchdog_feed(); // TODO do here? if(current_request_id == NO_ACTIVE_REQUEST_ID) { // find first request which is not acked or dropped int8_t found_next_req_index = bitmap_search(current_master_session.progress_bitmap, false, MODULE_D7AP_FIFO_MAX_REQUESTS_COUNT); if(found_next_req_index == -1 || found_next_req_index == current_master_session.next_request_id) { // we handled all requests ... flush_completed(); // TODO move callback to ALP? // if(d7asp_init_args != NULL && d7asp_init_args->d7asp_fifo_flush_completed_cb != NULL) // d7asp_init_args->d7asp_fifo_flush_completed_cb(fifo.token, fifo.progress_bitmap, fifo.success_bitmap, REQUESTS_BITMAP_BYTE_COUNT); return; } current_request_id = found_next_req_index; current_request_retry_count = 0; current_request_packet = packet_queue_alloc_packet(); packet_queue_mark_processing(current_request_packet); current_request_packet->d7anp_addressee = &(current_master_session.config.addressee); // TODO explicitly pass addressee down the stack layers? memcpy(current_request_packet->payload, current_master_session.request_buffer + current_master_session.requests_indices[current_request_id], current_master_session.requests_lengths[current_request_id]); current_request_packet->payload_length = current_master_session.requests_lengths[current_request_id]; // TODO calculate Tl and Tc // Tc(NB, LEN, CH) = (SFC * NB + 1) * TTX(CH, LEN) + TG with NB the number of concurrent devices and SF the collision Avoidance Spreading Factor // Tl should correspond to the maximum time needed to send the remaining requests in the FIFO including the RETRY parameter // For now, set Tc and Tl according the transmission_timeout_period set in the access profile dae_access_profile_t active_addressee_access_profile; fs_read_access_class(current_request_packet->d7anp_addressee->ctrl.access_class, &active_addressee_access_profile); current_request_packet->d7atp_tc = active_addressee_access_profile.transmission_timeout_period; current_request_packet->d7anp_listen_timeout = active_addressee_access_profile.transmission_timeout_period; } else { // retrying request ... DPRINT("Current request retry count: %i", current_request_retry_count); if(current_request_retry_count == single_request_retry_limit) { // mark request as failed and pop mark_current_request_done(); DPRINT("Request reached single request retry limit (%i), skipping request", single_request_retry_limit); packet_queue_free_packet(current_request_packet); current_request_id = NO_ACTIVE_REQUEST_ID; sched_post_task(&flush_fifos); // continue flushing until all request handled ... return; } // TODO stop on error } // TODO calculate D7ANP timeout (and update during transaction lifetime) (based on Tc, channel, cs, payload size, # msgs, # retries) d7atp_start_dialog(current_master_session.token, current_request_id, (current_request_id == current_master_session.next_request_id - 1), current_request_packet, ¤t_master_session.config.qos); }
/* will be feeding stuff into the encoding pipeline */ void * decode_thread(void *context) { OMX_BUFFERHEADERTYPE *input_buffer; // buffer taken from the OMX decoder OMX_PARAM_PORTDEFINITIONTYPE encoder_config; OMX_PARAM_PORTDEFINITIONTYPE decoder_config; OMX_PARAM_PORTDEFINITIONTYPE deinterlacer_config; OMX_VIDEO_PARAM_PORTFORMATTYPE encoder_format_config; //used for the output of the encoder OMX_VIDEO_PARAM_BITRATETYPE encoder_bitrate_config; //used for the output of the encoder struct transcoder_ctx_t *ctx = (struct transcoder_ctx_t *) context; struct packet_t *current_packet; int bytes_left; uint8_t *p; // points to currently copied buffer // omx_setup_encoding_pipeline(&decoder_ctx->pipeline, OMX_VIDEO_CodingAVC); omx_setup_encoding_pipeline(&ctx->pipeline, OMX_VIDEO_CodingMPEG2); // main loop that will poll packets and render while (ctx->input_video_queue->queue_count != 0 || ctx->input_video_queue->queue_finished != 1) { //TODO a memory barrier is going to be needed so that we don't race current_packet = packet_queue_get_next_item(ctx->input_video_queue); p = current_packet->data; bytes_left = current_packet->data_length; while (bytes_left > 0) { fprintf(stderr, "OMX buffers: v: %02d/20, vcodec queue: %4d\r", omx_get_free_buffer_count(&ctx->pipeline.video_decode), ctx->input_video_queue->queue_count); input_buffer = omx_get_next_input_buffer(&ctx->pipeline.video_decode); // This will block if there are no empty buffers // copy at most the length of the OMX buf int copy_length = OMX_MIN(bytes_left, input_buffer->nAllocLen); memcpy(input_buffer->pBuffer, p, copy_length); p += copy_length; bytes_left -= copy_length; input_buffer->nFilledLen = copy_length; input_buffer->nTimeStamp = pts_to_omx(current_packet->PTS); if (ctx->first_packet) { input_buffer->nFlags = OMX_BUFFERFLAG_STARTTIME; ctx->first_packet = 0; } else { //taken from ilclient input_buffer->nFlags = OMX_BUFFERFLAG_TIME_UNKNOWN; } if (current_packet->flags & AV_PKT_FLAG_KEY) { input_buffer->nFlags |= OMX_BUFFERFLAG_SYNCFRAME; } if(bytes_left == 0) { input_buffer->nFlags |= OMX_BUFFERFLAG_ENDOFFRAME; } //configure the resizer after the decoder has got output if (ctx->pipeline.video_decode.port_settings_changed == 1) { ctx->pipeline.video_decode.port_settings_changed = 0; #if 0 int x = 640; int y = 480; // rounding the dimensions up to the next multiple of 16. x += 0x0f; x &= ~0x0f; y += 0x0f; y &= ~0x0f; //the above code is used if resizer is used //get information about the decoded video OMX_INIT_STRUCTURE(decoder_config); decoder_config.nPortIndex = 131; OERR(OMX_GetParameter(ctx->pipeline.video_decode.h, OMX_IndexParamPortDefinition, &decoder_config)); decoder_config.nPortIndex = 190; OERR(OMX_GetParameter(ctx->pipeline.image_fx.h, OMX_IndexParamPortDefinition, &decoder_config)); decoder_config.nPortIndex = 191; OERR(OMX_GetParameter(ctx->pipeline.image_fx.h, OMX_IndexParamPortDefinition, &decoder_config)); #endif OERR(OMX_SetupTunnel(ctx->pipeline.video_decode.h, 131, ctx->pipeline.image_fx.h, 190)); omx_send_command_and_wait(&ctx->pipeline.video_decode, OMX_CommandPortEnable, 131, NULL); omx_send_command_and_wait(&ctx->pipeline.image_fx, OMX_CommandPortEnable, 190, NULL); omx_send_command_and_wait(&ctx->pipeline.image_fx, OMX_CommandStateSet, OMX_StateExecuting, NULL); fprintf(stderr, "configuring deinterlacer done\n"); } if(ctx->pipeline.image_fx.port_settings_changed == 1) { OMX_ERRORTYPE error; ctx->pipeline.image_fx.port_settings_changed = 0; #if 0 //get info from deinterlacer output OMX_INIT_STRUCTURE(deinterlacer_config); deinterlacer_config.nPortIndex = 191; OERR(OMX_GetParameter(ctx->pipeline.image_fx.h, OMX_IndexParamPortDefinition, &deinterlacer_config)); //get default from encoder input OMX_INIT_STRUCTURE(encoder_config); encoder_config.nPortIndex = 200; OERR(OMX_GetParameter(ctx->pipeline.video_encode.h, OMX_IndexParamPortDefinition, &encoder_config)); //modify it with deinterlacer encoder_config.format.video.nFrameHeight = deinterlacer_config.format.image.nFrameHeight; encoder_config.format.video.nFrameWidth = deinterlacer_config.format.image.nFrameWidth; encoder_config.format.video.eCompressionFormat = deinterlacer_config.format.image.eCompressionFormat; encoder_config.format.video.eColorFormat = deinterlacer_config.format.image.eColorFormat; encoder_config.format.video.nSliceHeight = deinterlacer_config.format.image.nSliceHeight; encoder_config.format.video.nStride = deinterlacer_config.format.image.nStride; //and feed it OERR(OMX_SetParameter(ctx->pipeline.video_encode.h, OMX_IndexParamPortDefinition, &encoder_config)); #endif //configure encoder output format OMX_INIT_STRUCTURE(encoder_format_config); encoder_format_config.nPortIndex = 201; //encoder output port encoder_format_config.eCompressionFormat = OMX_VIDEO_CodingAVC; OERR(OMX_SetParameter(ctx->pipeline.video_encode.h, OMX_IndexParamVideoPortFormat, &encoder_format_config)); //configure encoder output bitrate OMX_INIT_STRUCTURE(encoder_bitrate_config); encoder_bitrate_config.nPortIndex = 201; encoder_bitrate_config.eControlRate = OMX_Video_ControlRateVariable; //var bitrate encoder_bitrate_config.nTargetBitrate = ENCODED_BITRATE; //1 mbit OERR(OMX_SetParameter(ctx->pipeline.video_encode.h, OMX_IndexParamVideoBitrate, &encoder_bitrate_config)); //setup tunnel from decoder to encoder OERR(OMX_SetupTunnel(ctx->pipeline.image_fx.h, 191, ctx->pipeline.video_encode.h, 200)); //set encoder to idle after we have finished configuring it omx_send_command_and_wait0(&ctx->pipeline.video_encode, OMX_CommandStateSet, OMX_StateIdle, NULL); //allocate buffers for output of the encoder //send the enable command, which won't complete until the bufs are alloc'ed omx_send_command_and_wait0(&ctx->pipeline.video_encode, OMX_CommandPortEnable, 201, NULL); omx_alloc_buffers(&ctx->pipeline.video_encode, 201); //allocate output buffers //block until the port is fully enabled omx_send_command_and_wait1(&ctx->pipeline.video_encode, OMX_CommandPortEnable, 201, NULL); omx_send_command_and_wait1(&ctx->pipeline.video_encode, OMX_CommandStateSet, OMX_StateIdle, NULL); //enable the two ports omx_send_command_and_wait0(&ctx->pipeline.image_fx, OMX_CommandPortEnable, 191, NULL); omx_send_command_and_wait0(&ctx->pipeline.video_encode, OMX_CommandPortEnable, 200, NULL); omx_send_command_and_wait1(&ctx->pipeline.video_encode, OMX_CommandPortEnable, 200, NULL); omx_send_command_and_wait1(&ctx->pipeline.image_fx, OMX_CommandPortEnable, 191, NULL); omx_send_command_and_wait(&ctx->pipeline.video_encode, OMX_CommandStateSet, OMX_StateExecuting, NULL); fprintf(stderr, "finished configuring encoder\n"); } if(ctx->pipeline.video_encode.port_settings_changed == 1) { fprintf(stderr, "encoder enabled\n"); ctx->pipeline.video_encode.port_settings_changed = 0; //signal the consumer thread it can start polling for data ctx->pipeline.video_encode.is_running = 1; pthread_cond_signal(&ctx->pipeline.video_encode.is_running_cv); } OERR(OMX_EmptyThisBuffer(ctx->pipeline.video_decode.h, input_buffer)); } packet_queue_free_packet(current_packet, 1); current_packet = NULL; } printf("Finishing stream \n"); /* Indicate end of video stream */ input_buffer = omx_get_next_input_buffer(&ctx->pipeline.video_decode); input_buffer->nFilledLen = 0; input_buffer->nFlags = OMX_BUFFERFLAG_TIME_UNKNOWN | OMX_BUFFERFLAG_EOS; OERR(OMX_EmptyThisBuffer(ctx->pipeline.video_decode.h, input_buffer)); // omx_teardown_pipeline(&decoder_ctx->pipeline); }
static void release_packet(hw_radio_packet_t* hw_radio_packet) { packet_queue_free_packet(packet_queue_find_packet(hw_radio_packet)); }