diff --git a/Makefile.in b/Makefile.in index d50540bf7..fa1157b1d 100644 --- a/Makefile.in +++ b/Makefile.in @@ -108,6 +108,7 @@ OBJS = @OBJS@ \ src/utils/resource_manager.o \ src/utils/ring_buffer.o \ src/utils/timed_message.o \ + src/utils/wait_obj.o \ src/utils/worker.o \ src/vf_split.o \ src/video.o \ diff --git a/src/hd-rum-translator/hd-rum-recompress.cpp b/src/hd-rum-translator/hd-rum-recompress.cpp index af49e5a16..404bbaee9 100644 --- a/src/hd-rum-translator/hd-rum-recompress.cpp +++ b/src/hd-rum-translator/hd-rum-recompress.cpp @@ -95,9 +95,9 @@ static void *worker(void *arg) free_message(msg); } + compress_frame(s->compress, s->frame); struct video_frame *tx_frame = - compress_frame((struct compress_state *) s->compress, - s->frame, 0); + compress_pop(s->compress); if(tx_frame) { tx_send(s->tx, tx_frame, s->network_device); diff --git a/src/main.c b/src/main.c index 1910e3700..fa1b0e2bf 100644 --- a/src/main.c +++ b/src/main.c @@ -73,6 +73,7 @@ #include "rtp/pbuf.h" #include "sender.h" #include "stats.h" +#include "utils/wait_obj.h" #include "video.h" #include "video_capture.h" #include "video_display.h" @@ -723,6 +724,12 @@ void *ultragrid_rtp_receiver_thread(void *arg) return 0; } +static void uncompressed_frame_dispose(struct video_frame *frame) +{ + struct wait_obj *wait_obj = (struct wait_obj *) frame->dispose_udata; + wait_obj_notify(wait_obj); +} + /** * This function captures video and possibly compresses it. * It then delegates sending to another thread. @@ -736,11 +743,6 @@ static void *capture_thread(void *arg) struct sender_data sender_data; memset(&sender_data, 0, sizeof(sender_data)); - struct video_frame *tx_frame; - struct audio_frame *audio; - //struct video_frame *splitted_frames = NULL; - int i = 0; - struct compress_state *compression = NULL; int ret = compress_init(uv_mod, uv->requested_compression, &compression); if(ret != 0) { @@ -760,6 +762,10 @@ static void *capture_thread(void *arg) sender_data.tx_module_state = uv->rxtx_state; sender_data.send_frame = uv->rxtx->send; sender_data.uv = uv; + sender_data.video_exporter = uv->video_exporter; + sender_data.compression = compression; + + struct wait_obj *wait_obj = wait_obj_init(); if(!sender_init(&sender_data)) { fprintf(stderr, "Error initializing sender.\n"); @@ -772,34 +778,34 @@ static void *capture_thread(void *arg) while (!should_exit_sender) { /* Capture and transmit video... */ - tx_frame = vidcap_grab(uv->capture_device, &audio); + struct audio_frame *audio; + struct video_frame *tx_frame = vidcap_grab(uv->capture_device, &audio); + void (*old_dispose)(struct video_frame *) = NULL; + void *old_udata = NULL; if (tx_frame != NULL) { if(audio) { audio_sdi_send(uv->audio, audio); } - //TODO: Unghetto this - tx_frame = compress_frame(compression, tx_frame, i); - if(!tx_frame) - continue; + //tx_frame = vf_get_copy(tx_frame); + old_dispose = tx_frame->dispose; + old_udata = tx_frame->dispose_udata; + tx_frame->dispose = uncompressed_frame_dispose; + tx_frame->dispose_udata = wait_obj; + wait_obj_reset(wait_obj); - i = (i + 1) % 2; + // Sends frame to compression - this passes it to a sender thread + compress_frame(compression, tx_frame); - video_export(uv->video_exporter, tx_frame); - - bool nonblock = true; - /* when sending uncompressed video, we simply post it for send - * and wait until done */ - /* for compressed, we do not need to wait because of - * double-buffering of compression */ - if(is_compress_none(compression)) { - nonblock = false; - } - - sender_post_new_frame(&sender_data, tx_frame, nonblock); + // wait to frame is processed - eg by compress or sender (uncompressed video) + wait_obj_wait(wait_obj); + tx_frame->dispose = old_dispose; + tx_frame->dispose_udata = old_udata; } } + compress_frame(compression, NULL); // pass poisoned pill (will go through to the sender) sender_done(&sender_data); + wait_obj_done(wait_obj); compress_done: module_done(CAST_MODULE(compression)); diff --git a/src/rtp/video_decoders.cpp b/src/rtp/video_decoders.cpp index 6dbdfda96..48f6919bc 100644 --- a/src/rtp/video_decoders.cpp +++ b/src/rtp/video_decoders.cpp @@ -115,6 +115,7 @@ static void *decompress_thread(void *args); static void cleanup(struct state_video_decoder *decoder); static bool parse_video_hdr(uint32_t *hdr, struct video_desc *desc); +namespace { /** * Enumerates 2 possibilities how to decode arriving data. */ @@ -156,6 +157,74 @@ struct fec { struct decompress_msg; struct main_msg; +// message definitions +typedef char *char_p; +typedef struct packet_counter *packet_counter_p; +struct ldgm_msg { + ldgm_msg(int count) : substream_count(count) { + buffer_len = new int[count]; + buffer_num = new int[count]; + recv_buffers = new char_p[count]; + pckt_list = new packet_counter_p[count]; + } + ~ldgm_msg() { + delete buffer_len; + delete buffer_num; + delete recv_buffers; + for(int i = 0; i < substream_count; ++i) { + pc_destroy(pckt_list[i]); + } + delete pckt_list; + } + int *buffer_len; + int *buffer_num; + char **recv_buffers; + struct packet_counter **pckt_list; + int pt; + int k, m, c, seed; + int substream_count; + bool poisoned; +}; + +struct decompress_msg { + decompress_msg(int count) { + decompress_buffer = new char_p[count]; + fec_buffers = new char_p[count]; + buffer_len = new int[count]; + buffer_num = new int[count]; + } + ~decompress_msg() { + delete decompress_buffer; + delete fec_buffers; + delete buffer_len; + delete buffer_num; + } + char **decompress_buffer; + int *buffer_len; + int *buffer_num; + char **fec_buffers; + bool poisoned; +}; + +enum main_msg_type { + RECONFIGURE, +}; + +struct main_msg { + virtual ~main_msg(){} +}; + +struct main_msg_reconfigure : public main_msg { + main_msg_reconfigure(struct video_desc d) : desc(d) {} + struct video_desc desc; +}; + +struct video_new_prop : public main_msg { + double set_fps; + codec_t codec; +}; +} + /** * @brief Decoder state */ @@ -235,73 +304,6 @@ struct state_video_decoder { struct openssl_decrypt *decrypt; ///< decrypt state }; -// message definitions -typedef char *char_p; -typedef struct packet_counter *packet_counter_p; -struct ldgm_msg { - ldgm_msg(int count) : substream_count(count) { - buffer_len = new int[count]; - buffer_num = new int[count]; - recv_buffers = new char_p[count]; - pckt_list = new packet_counter_p[count]; - } - ~ldgm_msg() { - delete buffer_len; - delete buffer_num; - delete recv_buffers; - for(int i = 0; i < substream_count; ++i) { - pc_destroy(pckt_list[i]); - } - delete pckt_list; - } - int *buffer_len; - int *buffer_num; - char **recv_buffers; - struct packet_counter **pckt_list; - int pt; - int k, m, c, seed; - int substream_count; - bool poisoned; -}; - -struct decompress_msg { - decompress_msg(int count) { - decompress_buffer = new char_p[count]; - fec_buffers = new char_p[count]; - buffer_len = new int[count]; - buffer_num = new int[count]; - } - ~decompress_msg() { - delete decompress_buffer; - delete fec_buffers; - delete buffer_len; - delete buffer_num; - } - char **decompress_buffer; - int *buffer_len; - int *buffer_num; - char **fec_buffers; - bool poisoned; -}; - -enum main_msg_type { - RECONFIGURE, -}; - -struct main_msg { - virtual ~main_msg(){} -}; - -struct main_msg_reconfigure : public main_msg { - main_msg_reconfigure(struct video_desc d) : desc(d) {} - struct video_desc desc; -}; - -struct video_new_prop : public main_msg { - double set_fps; - codec_t codec; -}; - /** * This function blocks until video frame is displayed and decoder::frame * can be filled with new data. Until this point, the video frame is not considered diff --git a/src/sender.c b/src/sender.c index ea0ffb3fe..8e7898c19 100644 --- a/src/sender.c +++ b/src/sender.c @@ -67,11 +67,11 @@ #include "transmit.h" #include "vf_split.h" #include "video.h" +#include "video_compress.h" #include "video_display.h" +#include "video_export.h" -static struct sender_internal_msg *new_frame_msg(struct video_frame *frame); static void *sender_thread(void *arg); -static void sender_finish(struct sender_data *data); static void ultragrid_rtp_send(void *state, struct video_frame *tx_frame); static void ultragrid_rtp_done(void *state); static void sage_rxtx_send(void *state, struct video_frame *tx_frame); @@ -81,9 +81,6 @@ struct sender_priv_data { struct module mod; pthread_mutex_t lock; - pthread_cond_t msg_ready_cv; - pthread_cond_t msg_processed_cv; - struct sender_internal_msg *msg; pthread_t thread_id; bool paused; @@ -105,61 +102,6 @@ struct rx_tx sage_rxtx = { NULL }; -enum sender_msg_type { - FRAME, - QUIT -}; - -struct sender_internal_msg { - enum sender_msg_type type; - void *data; - void (*deleter)(struct sender_internal_msg *); -}; - -static struct sender_internal_msg *new_frame_msg(struct video_frame *frame) -{ - struct sender_internal_msg *msg = malloc(sizeof(struct sender_internal_msg)); - msg->type = FRAME; - msg->deleter = (void (*) (struct sender_internal_msg *)) free; - msg->data = frame; - - return msg; -} - -void sender_post_new_frame(struct sender_data *data, struct video_frame *frame, bool nonblock) { - pthread_mutex_lock(&data->priv->lock); - while(data->priv->msg) { - pthread_cond_wait(&data->priv->msg_processed_cv, &data->priv->lock); - } - - data->priv->msg = new_frame_msg(frame); - pthread_cond_signal(&data->priv->msg_ready_cv); - - if(!nonblock) { - // we wait until frame is completed - while(data->priv->msg) { - pthread_cond_wait(&data->priv->msg_processed_cv, &data->priv->lock); - } - } - pthread_mutex_unlock(&data->priv->lock); -} - -static void sender_finish(struct sender_data *data) { - pthread_mutex_lock(&data->priv->lock); - - while(data->priv->msg) { - pthread_cond_wait(&data->priv->msg_processed_cv, &data->priv->lock); - } - - data->priv->msg = malloc(sizeof(struct sender_internal_msg)); - data->priv->msg->type = QUIT; - data->priv->msg->deleter = (void (*) (struct sender_internal_msg *)) free; - - pthread_cond_signal(&data->priv->msg_ready_cv); - - pthread_mutex_unlock(&data->priv->lock); -} - static void sender_process_external_message(struct sender_data *data, struct msg_sender *msg) { int ret; @@ -192,9 +134,6 @@ static void sender_process_external_message(struct sender_data *data, struct msg bool sender_init(struct sender_data *data) { data->priv = calloc(1, sizeof(struct sender_priv_data)); pthread_mutex_init(&data->priv->lock, NULL); - pthread_cond_init(&data->priv->msg_ready_cv, NULL); - pthread_cond_init(&data->priv->msg_processed_cv, NULL); - data->priv->msg = NULL; // we lock and thred unlocks after initialized pthread_mutex_lock(&data->priv->lock); @@ -214,12 +153,8 @@ bool sender_init(struct sender_data *data) { } void sender_done(struct sender_data *data) { - sender_finish(data); pthread_join(data->priv->thread_id, NULL); - pthread_mutex_destroy(&data->priv->lock); - pthread_cond_destroy(&data->priv->msg_ready_cv); - pthread_cond_destroy(&data->priv->msg_processed_cv); free(data->priv); } @@ -311,34 +246,21 @@ static void *sender_thread(void *arg) { free_message(msg_external); } - pthread_mutex_lock(&data->priv->lock); struct video_frame *tx_frame = NULL; - while(!data->priv->msg) { - pthread_cond_wait(&data->priv->msg_ready_cv, &data->priv->lock); - } - struct sender_internal_msg *msg = data->priv->msg; - switch (msg->type) { - case QUIT: - data->priv->msg = NULL; - msg->deleter(msg); - pthread_cond_broadcast(&data->priv->msg_processed_cv); - pthread_mutex_unlock(&data->priv->lock); - goto exit; - case FRAME: - tx_frame = msg->data; - break; - default: - abort(); - } - - pthread_mutex_unlock(&data->priv->lock); + tx_frame = compress_pop(data->compression); + if (!tx_frame) + goto exit; if(data->priv->paused) { goto after_send; } + video_export(data->video_exporter, tx_frame); + data->send_frame(data->tx_module_state, tx_frame); + if (tx_frame->dispose) + tx_frame->dispose(tx_frame); after_send: @@ -348,13 +270,6 @@ after_send: rtp_get_bytes_sent(rtp_state->network_devices[0])); } - pthread_mutex_lock(&data->priv->lock); - - data->priv->msg = NULL; - msg->deleter(msg); - - pthread_cond_broadcast(&data->priv->msg_processed_cv); - pthread_mutex_unlock(&data->priv->lock); } exit: diff --git a/src/sender.h b/src/sender.h index 2fc92f51f..4d68b8d92 100644 --- a/src/sender.h +++ b/src/sender.h @@ -71,6 +71,7 @@ struct received_message; struct response; struct sender_msg; struct sender_priv_data; +struct video_compress; enum rxtx_protocol { ULTRAGRID_RTP, @@ -93,6 +94,8 @@ struct sender_data { void *tx_module_state; struct state_uv *uv; struct sender_priv_data *priv; + struct video_export *video_exporter; + struct compress_state *compression; }; extern struct rx_tx ultragrid_rtp; @@ -112,7 +115,6 @@ struct sage_rxtx_state { bool sender_init(struct sender_data *data); void sender_done(struct sender_data *data); -void sender_post_new_frame(struct sender_data *data, struct video_frame *frame, bool nonblock); #endif // SENDER_H_ diff --git a/src/types.h b/src/types.h index bec109bda..cd7aaf0aa 100644 --- a/src/types.h +++ b/src/types.h @@ -133,11 +133,25 @@ struct video_frame { unsigned int frame_fragment_id:14; /// @} + /// @{ + /** + * This function (if defined) is called when frame is no longer needed + * by processing queue. + * @note + * Currently, this is only used in sending workflow, not the receiving one! + * Can be called from arbitrary thread. + */ + void (*dispose)(struct video_frame *); + /** + * Additional data needed to dispose the frame + */ + void *dispose_udata; /** * This function (if defined) is called by vf_free() to destruct video data * (@ref tile::data members). */ void (*data_deleter)(struct video_frame *); + /// @} }; /** diff --git a/src/utils/wait_obj.cpp b/src/utils/wait_obj.cpp new file mode 100644 index 000000000..8338c7273 --- /dev/null +++ b/src/utils/wait_obj.cpp @@ -0,0 +1,68 @@ +/** + * @file utils/wait_obj.h + * @author Martin Pulec + */ +/* + * Copyright (c) 2013 CESNET z.s.p.o. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, is permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of CESNET nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "config_unix.h" +#include "config_win32.h" + +#include "utils/wait_obj.h" + +struct wait_obj *wait_obj_init() +{ + return new wait_obj; +} + +void wait_obj_reset(struct wait_obj *wait_obj) +{ + wait_obj->reset(); +} + +void wait_obj_wait(struct wait_obj *wait_obj) +{ + wait_obj->wait(); +} + +void wait_obj_notify(struct wait_obj *wait_obj) +{ + wait_obj->notify(); +} + +void wait_obj_done(struct wait_obj *wait_obj) +{ + delete wait_obj; +} + diff --git a/src/utils/wait_obj.h b/src/utils/wait_obj.h new file mode 100644 index 000000000..4375061f5 --- /dev/null +++ b/src/utils/wait_obj.h @@ -0,0 +1,94 @@ +/** + * @file utils/wait_obj.h + * @author Martin Pulec + */ +/* + * Copyright (c) 2013 CESNET z.s.p.o. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, is permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of CESNET nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef UTILS_WAIT_OBJ_H_ +#define UTILS_WAIT_OBJ_H_ + +#ifdef __cplusplus +#include "utils/lock_guard.h" +struct wait_obj { + public: + wait_obj() : m_val(false) { + pthread_mutex_init(&m_lock, NULL); + pthread_cond_init(&m_cv, NULL); + } + ~wait_obj() { + pthread_mutex_destroy(&m_lock); + pthread_cond_destroy(&m_cv); + } + void wait() { + lock_guard guard(m_lock); + while (!m_val) + pthread_cond_wait(&m_cv, &m_lock); + } + void reset() { + lock_guard guard(m_lock); + m_val = false; + } + void notify() { + lock_guard guard(m_lock); + m_val = true; + pthread_cond_signal(&m_cv); + } + private: + pthread_mutex_t m_lock; + pthread_cond_t m_cv; + bool m_val; +}; +#endif // __cplusplus + +struct wait_obj; + +// +// C wrapper +// +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +struct wait_obj *wait_obj_init(void); +void wait_obj_reset(struct wait_obj *); +void wait_obj_wait(struct wait_obj *); +void wait_obj_notify(struct wait_obj *); +void wait_obj_done(struct wait_obj *); + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif // VIDEO_H_ + diff --git a/src/video_compress.c b/src/video_compress.cpp similarity index 88% rename from src/video_compress.c rename to src/video_compress.cpp index 2b42dd6e1..18ed11c84 100644 --- a/src/video_compress.c +++ b/src/video_compress.cpp @@ -57,8 +57,10 @@ #include "video_compress/none.h" #include "video_compress/uyvy.h" #include "lib_common.h" +#include "utils/message_queue.h" #include "utils/worker.h" +namespace { /* *_str are symbol names inside library */ /** * @brief This struct describes individual compress module @@ -81,6 +83,12 @@ struct compress_t { const char *compress_frame_str; compress_tile_t compress_tile_func; ///< compress function for Tile API const char *compress_tile_str; + /** + * Async readback function. + * If not defined, synchronous API is supposed. + */ + compress_pop_t compress_pop_func; + const char *compress_pop_str; void *handle; ///< for modular build, dynamically loaded library handle }; @@ -99,8 +107,17 @@ struct compress_state_real { * uses tile API. In this case returned tiles are * arranged to frame. * @see compress_t */ + message_queue *queue; + + int buffer_index; }; +struct msg_frame : public msg { + msg_frame(struct video_frame *f) : frame(f) {} + struct video_frame *frame; +}; +} + /** * @brief Video compress state. * @@ -140,6 +157,7 @@ struct compress_t compress_modules[] = { MK_NAME(fastdxt_init), MK_NAME(NULL), MK_NAME(fastdxt_compress_tile), + MK_NAME(NULL), NULL }, #endif @@ -150,6 +168,7 @@ struct compress_t compress_modules[] = { MK_NAME(dxt_glsl_compress_init), MK_NAME(dxt_glsl_compress), MK_NAME(NULL), + MK_NAME(NULL), NULL }, #endif @@ -160,6 +179,7 @@ struct compress_t compress_modules[] = { MK_NAME(jpeg_compress_init), MK_NAME(jpeg_compress), MK_NAME(NULL), + MK_NAME(NULL), NULL }, #endif @@ -170,6 +190,7 @@ struct compress_t compress_modules[] = { MK_NAME(uyvy_compress_init), MK_NAME(uyvy_compress), MK_NAME(NULL), + MK_NAME(NULL), NULL }, #endif @@ -180,6 +201,7 @@ struct compress_t compress_modules[] = { MK_NAME(libavcodec_compress_init), MK_NAME(NULL), MK_NAME(libavcodec_compress_tile), + MK_NAME(NULL), NULL }, #endif @@ -190,6 +212,7 @@ struct compress_t compress_modules[] = { MK_NAME(cuda_dxt_compress_init), MK_NAME(NULL), MK_NAME(cuda_dxt_compress_tile), + MK_NAME(NULL), NULL }, #endif @@ -199,6 +222,7 @@ struct compress_t compress_modules[] = { MK_STATIC(none_compress_init), MK_STATIC(none_compress), MK_STATIC(NULL), + MK_NAME(NULL), NULL }, }; @@ -341,7 +365,7 @@ int compress_init(struct module *parent, const char *config_string, struct compr struct compress_state_real *s; compress_state_proxy *proxy; - proxy = malloc(sizeof(compress_state_proxy)); + proxy = (compress_state_proxy *) malloc(sizeof(compress_state_proxy)); module_init_default(&proxy->mod); proxy->mod.cls = MODULE_CLASS_COMPRESS; @@ -374,11 +398,11 @@ static int compress_init_real(struct module *parent, const char *config_string, struct compress_state_real **state) { struct compress_state_real *s; - char *compress_options = NULL; - - if(!config_string) + const char *compress_options = NULL; + + if(!config_string) return -1; - + if(strcmp(config_string, "help") == 0) { show_compress_help(); @@ -386,15 +410,17 @@ static int compress_init_real(struct module *parent, const char *config_string, } pthread_once(&compression_list_initialized, init_compressions); - + s = (struct compress_state_real *) calloc(1, sizeof(struct compress_state_real)); + s->queue = new message_queue(1); + s->state_count = 1; int i; for(i = 0; i < compress_modules_count; ++i) { if(strncasecmp(config_string, available_compress_modules[i]->name, strlen(available_compress_modules[i]->name)) == 0) { s->handle = available_compress_modules[i]; - if(config_string[strlen(available_compress_modules[i]->name)] == ':') + if(config_string[strlen(available_compress_modules[i]->name)] == ':') compress_options = config_string + strlen(available_compress_modules[i]->name) + 1; else @@ -409,7 +435,7 @@ static int compress_init_real(struct module *parent, const char *config_string, strncpy(s->compress_options, compress_options, sizeof(s->compress_options) - 1); s->compress_options[sizeof(s->compress_options) - 1] = '\0'; if(s->handle->init_func) { - s->state = calloc(1, sizeof(struct module *)); + s->state = (struct module **) calloc(1, sizeof(struct module *)); s->state[0] = s->handle->init_func(parent, s->compress_options); if(!s->state[0]) { fprintf(stderr, "Compression initialization failed: %s\n", config_string); @@ -457,27 +483,45 @@ const char *get_compress_name(compress_state_proxy *proxy) * same index. * @return compressed frame, may be NULL if compression failed */ -struct video_frame *compress_frame(compress_state_proxy *proxy, struct video_frame *frame, int buffer_index) +void compress_frame(compress_state_proxy *proxy, struct video_frame *frame) { - struct video_frame *ret; - if(!proxy) - return NULL; + if (!proxy) + abort(); + + struct compress_state_real *s = proxy->ptr; + + if (frame == NULL) { // pass poisoned pill + s->queue->push(new msg_frame(NULL)); + return; + } + struct msg_change_compress_data *msg = NULL; while ((msg = (struct msg_change_compress_data *) check_message(&proxy->mod))) { compress_process_message(proxy, msg); } - struct compress_state_real *s = proxy->ptr; - + struct video_frame *sync_api_frame; if(s->handle->compress_frame_func) { - ret = s->handle->compress_frame_func(s->state[0], frame, buffer_index); + sync_api_frame = s->handle->compress_frame_func(s->state[0], frame, s->buffer_index); } else if(s->handle->compress_tile_func) { - ret = compress_frame_tiles(s, frame, buffer_index, &proxy->mod); + sync_api_frame = compress_frame_tiles(s, frame, s->buffer_index, &proxy->mod); } else { - ret = NULL; + sync_api_frame = NULL; } - return ret; + s->buffer_index = (s->buffer_index + 1) % 2; + // returned frame is different, so we may dispose the previous one + if (sync_api_frame != frame) { + frame->dispose(frame); + } + + msg_frame *frame_msg; + if (s->handle->compress_pop_func) { + abort(); // not yet implemented + } else { + frame_msg = new msg_frame(sync_api_frame); + } + s->queue->push(frame_msg); } /** @@ -489,7 +533,7 @@ struct video_frame *compress_frame(compress_state_proxy *proxy, struct video_fra * @brief Auxiliary structure passed to worker thread. */ struct compress_worker_data { - void *state; ///< compress driver status + struct module *state; ///< compress driver status struct tile *tile; ///< uncompressed tile to be compressed struct video_desc desc; ///< IN - src video description; OUT - compressed description int buffer_index; ///< buffer index @see compress_frame @@ -531,7 +575,7 @@ static void vf_write_desc(struct video_frame *buf, struct video_desc desc) /** * Compresses video frame with tiles API - * + * * @param[in] s compress state * @param[in] frame uncompressed frame * @param buffer_index 0 or 1 - driver should have 2 output buffers, filling the selected one. @@ -544,7 +588,7 @@ static struct video_frame *compress_frame_tiles(struct compress_state_real *s, s int buffer_index, struct module *parent) { if(frame->tile_count != s->state_count) { - s->state = realloc(s->state, frame->tile_count * sizeof(struct module *)); + s->state = (struct module **) realloc(s->state, frame->tile_count * sizeof(struct module *)); for(unsigned int i = s->state_count; i < frame->tile_count; ++i) { s->state[i] = s->handle->init_func(parent, s->compress_options); if(!s->state[i]) { @@ -575,7 +619,8 @@ static struct video_frame *compress_frame_tiles(struct compress_state_real *s, s } for(unsigned int i = 0; i < frame->tile_count; ++i) { - struct compress_worker_data *data = wait_task(task_handle[i]); + struct compress_worker_data *data = (struct compress_worker_data *) + wait_task(task_handle[i]); if(i == 0) { // update metadata from first tile data->desc.tile_count = frame->tile_count; @@ -604,7 +649,7 @@ static void compress_done(struct module *mod) if(!mod) return; - compress_state_proxy *proxy = mod->priv_data; + compress_state_proxy *proxy = (compress_state_proxy *) mod->priv_data; struct compress_state_real *s = proxy->ptr; compress_done_real(s); @@ -625,19 +670,28 @@ static void compress_done_real(struct compress_state_real *s) module_done(s->state[i]); } free(s->state); + delete s->queue; free(s); } -/** - * @brief Returns whether we are using dummy (none) compression or not. - * @param proxy video compress state - * @retval TRUE video compress is a dummy one - * @retval FALSE We are using some non-trivial video compression. - */ -int is_compress_none(compress_state_proxy *proxy) +struct video_frame *compress_pop(compress_state_proxy *proxy) { - assert(proxy != NULL); + struct video_frame *ret = NULL; + if(!proxy) + return NULL; - return strcmp("none", get_compress_name(proxy)) == 0 ? TRUE : FALSE; + struct compress_state_real *s = proxy->ptr; + + if(s->handle->compress_pop_func) { + // ret = s->handle->compress_pop_func(s->state[0], frame, buffer_index); + } else { + msg *message = s->queue->pop(); + msg_frame *frame_msg = dynamic_cast(message); + assert(frame_msg != NULL); + ret = frame_msg->frame; + delete frame_msg; + } + + return ret; } diff --git a/src/video_compress.h b/src/video_compress.h index aaea26806..a4f9025d0 100644 --- a/src/video_compress.h +++ b/src/video_compress.h @@ -90,15 +90,23 @@ typedef struct video_frame * (*compress_frame_t)(struct module *state, struct v */ typedef struct tile * (*compress_tile_t)(struct module *state, struct tile *tile, struct video_desc *desc, int buffer_index); +/** + * @brief Gets back tile/frame from driver + * + * @param[in] state driver internal state + * @param[out] desc output video desc (only for tiles - for frames this is directly in metadata_ + * @retval !=NULL compressed tile/frame + * @retval NULL signal that queue has finished + */ +typedef void * (*compress_pop_t)(struct module *state, struct video_desc *desc); /// @} void show_compress_help(void); int compress_init(struct module *parent, const char *config_string, struct compress_state **); const char *get_compress_name(struct compress_state *); -int is_compress_none(struct compress_state *); - -struct video_frame *compress_frame(struct compress_state *, struct video_frame*, int buffer_index); +void compress_frame(struct compress_state *, struct video_frame*); +struct video_frame *compress_pop(struct compress_state *); #ifdef __cplusplus } diff --git a/src/video_compress/dxt_glsl.h b/src/video_compress/dxt_glsl.h index 086604afd..ff7d459c9 100644 --- a/src/video_compress/dxt_glsl.h +++ b/src/video_compress/dxt_glsl.h @@ -1,32 +1,25 @@ -/* - * FILE: dxt_glsl_compress.h - * AUTHORS: Martin Benes - * Lukas Hejtmanek - * Petr Holub - * Milos Liska - * Jiri Matela - * Dalibor Matura <255899@mail.muni.cz> - * Ian Wesley-Smith +/** + * @file video_compress/dxt_glsl.h + * @author Martin Pulec * - * Copyright (c) 2005-2010 CESNET z.s.p.o. + * @brief This is an umbrella header for video functions. + */ +/* + * Copyright (c) 2011-2013 CESNET z.s.p.o. + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, is permitted provided that the following conditions * are met: - * + * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * - * This product includes software developed by CESNET z.s.p.o. - * - * 4. Neither the name of the CESNET nor the names of its contributors may be + * + * 3. Neither the name of CESNET nor the names of its contributors may be * used to endorse or promote products derived from this software without * specific prior written permission. * @@ -42,9 +35,9 @@ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * */ + #ifdef HAVE_CONFIG_H #include "config.h" #include "config_unix.h" @@ -54,6 +47,14 @@ struct video_frame; struct module; +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + struct module *dxt_glsl_compress_init(struct module *parent, const char *opts); struct video_frame *dxt_glsl_compress(struct module *mod, struct video_frame * tx, int buffer_index); +#ifdef __cplusplus +} +#endif // __cplusplus + diff --git a/src/video_compress/fastdxt.h b/src/video_compress/fastdxt.h index fc88b3753..78bedaeec 100644 --- a/src/video_compress/fastdxt.h +++ b/src/video_compress/fastdxt.h @@ -1,32 +1,25 @@ -/* - * FILE: video_compress.h - * AUTHORS: Martin Benes - * Lukas Hejtmanek - * Petr Holub - * Milos Liska - * Jiri Matela - * Dalibor Matura <255899@mail.muni.cz> - * Ian Wesley-Smith +/** + * @file video_compress/fastdxt.h + * @author Martin Pulec * - * Copyright (c) 2005-2010 CESNET z.s.p.o. + * @brief This is an umbrella header for video functions. + */ +/* + * Copyright (c) 2011-2013 CESNET z.s.p.o. + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, is permitted provided that the following conditions * are met: - * + * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * - * This product includes software developed by CESNET z.s.p.o. - * - * 4. Neither the name of the CESNET nor the names of its contributors may be + * + * 3. Neither the name of CESNET nor the names of its contributors may be * used to endorse or promote products derived from this software without * specific prior written permission. * @@ -42,7 +35,6 @@ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * */ #ifdef HAVE_CONFIG_H @@ -51,10 +43,18 @@ #include "config_win32.h" #endif // HAVE_CONFIG_H -struct modul; +struct module; struct tile; struct video_desc; +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + struct module *fastdxt_init(struct module *parent, const char *num_threads_str); struct tile *fastdxt_compress_tile(struct module *mod, struct tile * tx, struct video_desc *desc, int buffer_index); +#ifdef __cplusplus +} +#endif // __cplusplus + diff --git a/src/video_compress/jpeg.h b/src/video_compress/jpeg.h index df1400ca0..17544ec72 100644 --- a/src/video_compress/jpeg.h +++ b/src/video_compress/jpeg.h @@ -1,32 +1,25 @@ -/* - * FILE: dxt_glsl_compress.h - * AUTHORS: Martin Benes - * Lukas Hejtmanek - * Petr Holub - * Milos Liska - * Jiri Matela - * Dalibor Matura <255899@mail.muni.cz> - * Ian Wesley-Smith +/** + * @file video_compress/jpeg.h + * @author Martin Pulec * - * Copyright (c) 2005-2010 CESNET z.s.p.o. + * @brief This is an umbrella header for video functions. + */ +/* + * Copyright (c) 2011-2013 CESNET z.s.p.o. + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, is permitted provided that the following conditions * are met: - * + * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * - * This product includes software developed by CESNET z.s.p.o. - * - * 4. Neither the name of the CESNET nor the names of its contributors may be + * + * 3. Neither the name of CESNET nor the names of its contributors may be * used to endorse or promote products derived from this software without * specific prior written permission. * @@ -42,18 +35,26 @@ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * */ + #ifdef HAVE_CONFIG_H #include "config.h" #include "config_unix.h" #include "config_win32.h" #endif // HAVE_CONFIG_H +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + struct module; struct video_frame; struct module *jpeg_compress_init(struct module *parent, const char *opts); struct video_frame *jpeg_compress(struct module *mod, struct video_frame * tx, int buffer_index); +#ifdef __cplusplus +} +#endif // __cplusplus + diff --git a/src/video_compress/libavcodec.h b/src/video_compress/libavcodec.h index 205058834..74357aa0a 100644 --- a/src/video_compress/libavcodec.h +++ b/src/video_compress/libavcodec.h @@ -1,32 +1,25 @@ -/* - * FILE: video_compress.h - * AUTHORS: Martin Benes - * Lukas Hejtmanek - * Petr Holub - * Milos Liska - * Jiri Matela - * Dalibor Matura <255899@mail.muni.cz> - * Ian Wesley-Smith +/** + * @file video_compress/libavcodec.h + * @author Martin Pulec * - * Copyright (c) 2005-2010 CESNET z.s.p.o. + * @brief This is an umbrella header for video functions. + */ +/* + * Copyright (c) 2013 CESNET z.s.p.o. + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, is permitted provided that the following conditions * are met: - * + * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * - * This product includes software developed by CESNET z.s.p.o. - * - * 4. Neither the name of the CESNET nor the names of its contributors may be + * + * 3. Neither the name of CESNET nor the names of its contributors may be * used to endorse or promote products derived from this software without * specific prior written permission. * @@ -42,9 +35,12 @@ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * */ +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + struct module; struct tile; struct video_desc; @@ -53,3 +49,7 @@ struct module *libavcodec_compress_init(struct module *parent, const char struct tile *libavcodec_compress_tile(struct module *mod, struct tile *tx, struct video_desc *desc, int buffer); +#ifdef __cplusplus +} +#endif // __cplusplus + diff --git a/src/video_compress/none.h b/src/video_compress/none.h index 3dae17768..9092d8626 100644 --- a/src/video_compress/none.h +++ b/src/video_compress/none.h @@ -1,14 +1,16 @@ +/** + * @file none.h + * @author Martin Benes + * @author Lukas Hejtmanek + * @author Petr Holub + * @author Milos Liska + * @author Jiri Matela + * @author Dalibor Matura <255899@mail.muni.cz> + * @author Martin Pulec + * @author Ian Wesley-Smith + */ /* - * FILE: none.h - * AUTHORS: Martin Benes - * Lukas Hejtmanek - * Petr Holub - * Milos Liska - * Jiri Matela - * Dalibor Matura <255899@mail.muni.cz> - * Ian Wesley-Smith - * - * Copyright (c) 2005-2010 CESNET z.s.p.o. + * Copyright (c) 2005-2013 CESNET z.s.p.o. * * Redistribution and use in source and binary forms, with or without * modification, is permitted provided that the following conditions @@ -45,11 +47,9 @@ * */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#include "config_unix.h" -#include "config_win32.h" -#endif // HAVE_CONFIG_H +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus struct module; struct video_frame; @@ -57,3 +57,7 @@ struct video_frame; struct module *none_compress_init(struct module *parent, const char *opts); struct video_frame *none_compress(struct module *mod, struct video_frame * tx, int buffer_index); +#ifdef __cplusplus +} +#endif // __cplusplus + diff --git a/src/video_compress/uyvy.h b/src/video_compress/uyvy.h index 888180f61..3b8c96546 100644 --- a/src/video_compress/uyvy.h +++ b/src/video_compress/uyvy.h @@ -1,32 +1,25 @@ -/* - * FILE: dxt_glsl_compress.h - * AUTHORS: Martin Benes - * Lukas Hejtmanek - * Petr Holub - * Milos Liska - * Jiri Matela - * Dalibor Matura <255899@mail.muni.cz> - * Ian Wesley-Smith +/** + * @file video_compress/uyvy.h + * @author Martin Pulec * - * Copyright (c) 2005-2010 CESNET z.s.p.o. + * @brief This is an umbrella header for video functions. + */ +/* + * Copyright (c) 2012-2013 CESNET z.s.p.o. + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, is permitted provided that the following conditions * are met: - * + * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * - * This product includes software developed by CESNET z.s.p.o. - * - * 4. Neither the name of the CESNET nor the names of its contributors may be + * + * 3. Neither the name of CESNET nor the names of its contributors may be * used to endorse or promote products derived from this software without * specific prior written permission. * @@ -42,12 +35,19 @@ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * */ +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + struct module; struct video_frame; struct module *uyvy_compress_init(struct module *parent, const char *opts); struct video_frame *uyvy_compress(struct module *mod, struct video_frame * tx, int buffer); +#ifdef __cplusplus +} +#endif // __cplusplus + diff --git a/src/video_decompress/jpeg_to_dxt.cpp b/src/video_decompress/jpeg_to_dxt.cpp index 442782554..cf18cdf77 100644 --- a/src/video_decompress/jpeg_to_dxt.cpp +++ b/src/video_decompress/jpeg_to_dxt.cpp @@ -56,6 +56,8 @@ #include "video_decompress.h" #include "video_decompress/jpeg.h" +namespace { + struct thread_data { thread_data() : m_in(1), m_out(1), @@ -112,6 +114,8 @@ struct state_decompress_jpeg_to_dxt { }; +} // namespace + static int reconfigure_thread(struct thread_data *s, struct video_desc desc, int ppb); static void *worker_thread(void *arg)