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 ...
}
Esempio n. 2
0
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;
}
Esempio n. 5
0
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);
        }
    }
}
Esempio n. 8
0
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
}
Esempio n. 9
0
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 == &current_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, &current_master_session.config.qos);
}
Esempio n. 12
0
/* 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));
}