mirror of
https://github.com/outbackdingo/UltraGrid.git
synced 2026-03-22 06:40:26 +00:00
Added possibility to send throught multiple links
+ basis for 4K transmit
This commit is contained in:
@@ -35,6 +35,7 @@ OBJS = src/bitstream.o \
|
||||
src/crypto/md5.o \
|
||||
src/crypto/random.o \
|
||||
src/video_codec.o \
|
||||
src/tile.o \
|
||||
src/video_capture.o \
|
||||
src/video_capture/null.o \
|
||||
@DVS_OBJ@ \
|
||||
|
||||
@@ -84,8 +84,13 @@
|
||||
#define EXIT_FAIL_NETWORK 5
|
||||
#define EXIT_FAIL_TRANSMIT 6
|
||||
|
||||
#define PORT_BASE 5004
|
||||
#define PORT_AUDIO 5006
|
||||
|
||||
struct state_uv {
|
||||
struct rtp *network_device;
|
||||
struct rtp **network_devices;
|
||||
unsigned int connections_count;
|
||||
int split_frames;
|
||||
struct rtp *audio_network_device;
|
||||
struct vidcap *capture_device;
|
||||
struct timeval start_time, curr_time;
|
||||
@@ -131,7 +136,7 @@ static void usage(void)
|
||||
{
|
||||
/* TODO -c -p -b are deprecated options */
|
||||
printf
|
||||
("Usage: uv [-d <display_device>] [-t <capture_device>] [-g <cfg>] [-m <mtu>] [-f <framerate>] [-c] [-p] [-i] [-b <8|10>] address\n\n");
|
||||
("Usage: uv [-d <display_device>] [-t <capture_device>] [-g <cfg>] [-m <mtu>] [-f <framerate>] [-c] [-p] [-i] [-b <8|10>] [-S] address(es)\n\n");
|
||||
printf
|
||||
("\t-d <display_device>\tselect display device, use -d help to get\n");
|
||||
printf("\t \tlist of devices availabe\n");
|
||||
@@ -143,6 +148,10 @@ static void usage(void)
|
||||
("\t \tuse -g help with a device to get info about\n");
|
||||
printf("\t \tsupported capture/display modes\n");
|
||||
printf("\t-i \tiHDTV compatibility mode\n");
|
||||
printf("\t-S \tsplit frame (multilink mode)\n");
|
||||
printf("\taddresses \tcomma-separated list of destination interfaces'\n");
|
||||
printf("\t \taddresses (splitted frame or tiled video)\n");
|
||||
printf("\t \tfirst case implies '-S' argument\n");
|
||||
}
|
||||
|
||||
void list_video_display_devices()
|
||||
@@ -226,20 +235,71 @@ static struct vidcap *initialize_video_capture(const char *requested_capture,
|
||||
return vidcap_init(id, fmt);
|
||||
}
|
||||
|
||||
static struct rtp *initialize_network(char *addr, struct pdb *participants)
|
||||
static struct rtp **initialize_network(char *addrs, struct pdb *participants)
|
||||
{
|
||||
struct rtp *r;
|
||||
struct rtp **devices = NULL;
|
||||
double rtcp_bw = 5 * 1024 * 1024; /* FIXME */
|
||||
int ttl = 255;
|
||||
char *saveptr;
|
||||
char *addr;
|
||||
char *tmp;
|
||||
int required_connections, index;
|
||||
int port = PORT_BASE;
|
||||
|
||||
r = rtp_init(addr, 5004, 5004, 255, rtcp_bw, FALSE, rtp_recv_callback,
|
||||
(void *)participants);
|
||||
if (r != NULL) {
|
||||
pdb_add(participants, rtp_my_ssrc(r));
|
||||
rtp_set_option(r, RTP_OPT_WEAK_VALIDATION, TRUE);
|
||||
rtp_set_sdes(r, rtp_my_ssrc(r), RTCP_SDES_TOOL,
|
||||
ULTRAGRID_VERSION, strlen(ULTRAGRID_VERSION));
|
||||
}
|
||||
return r;
|
||||
tmp = strdup(addrs);
|
||||
if(strtok_r(tmp, ",", &saveptr) == NULL) {
|
||||
free(tmp);
|
||||
return NULL;
|
||||
}
|
||||
else required_connections = 1;
|
||||
while(strtok_r(NULL, ",", &saveptr) != NULL)
|
||||
++required_connections;
|
||||
|
||||
free(tmp);
|
||||
tmp = strdup(addrs);
|
||||
|
||||
devices = (struct rtp **)
|
||||
malloc((required_connections + 1) * sizeof(struct rtp *));
|
||||
|
||||
for(index = 0, addr = strtok_r(addrs, ",", &saveptr);
|
||||
index < required_connections;
|
||||
++index, addr = strtok_r(NULL, ",", &saveptr), port += 2)
|
||||
{
|
||||
if (port == PORT_AUDIO)
|
||||
port += 2;
|
||||
devices[index] = rtp_init(addr, port, port, ttl, rtcp_bw,
|
||||
FALSE, rtp_recv_callback,
|
||||
(void *)participants);
|
||||
if (devices[index] != NULL) {
|
||||
rtp_set_option(devices[index], RTP_OPT_WEAK_VALIDATION,
|
||||
TRUE);
|
||||
rtp_set_sdes(devices[index], rtp_my_ssrc(devices[index]),
|
||||
RTCP_SDES_TOOL,
|
||||
ULTRAGRID_VERSION, strlen(ULTRAGRID_VERSION));
|
||||
pdb_add(participants, rtp_my_ssrc(devices[index]));
|
||||
}
|
||||
else {
|
||||
int index_nest;
|
||||
for(index_nest = 0; index_nest < index; ++index_nest) {
|
||||
rtp_done(devices[index_nest]);
|
||||
}
|
||||
free(devices);
|
||||
devices = NULL;
|
||||
}
|
||||
}
|
||||
if(devices != NULL) devices[index] = NULL;
|
||||
free(tmp);
|
||||
|
||||
return devices;
|
||||
}
|
||||
|
||||
static void destroy_devices(struct rtp ** network_devices)
|
||||
{
|
||||
struct rtp ** current = network_devices;
|
||||
while(current != NULL) {
|
||||
rtp_done(*current++);
|
||||
}
|
||||
free(network_devices);
|
||||
}
|
||||
|
||||
static struct video_tx *initialize_transmit(unsigned requested_mtu)
|
||||
@@ -426,8 +486,8 @@ static void *receiver_thread(void *arg)
|
||||
/* Housekeeping and RTCP... */
|
||||
gettimeofday(&uv->curr_time, NULL);
|
||||
uv->ts = tv_diff(uv->curr_time, uv->start_time) * 90000;
|
||||
rtp_update(uv->network_device, uv->curr_time);
|
||||
rtp_send_ctrl(uv->network_device, uv->ts, 0, uv->curr_time);
|
||||
rtp_update(uv->network_devices[0], uv->curr_time);
|
||||
rtp_send_ctrl(uv->network_devices[0], uv->ts, 0, uv->curr_time);
|
||||
|
||||
/* Receive packets from the network... The timeout is adjusted */
|
||||
/* to match the video capture rate, so the transmitter works. */
|
||||
@@ -439,7 +499,7 @@ static void *receiver_thread(void *arg)
|
||||
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = 999999 / 59.94;
|
||||
ret = rtp_recv(uv->network_device, &timeout, uv->ts);
|
||||
ret = rtp_recv_poll(uv->network_devices, &timeout, uv->ts);
|
||||
|
||||
/*
|
||||
if (ret == FALSE) {
|
||||
@@ -483,6 +543,19 @@ static void *sender_thread(void *arg)
|
||||
|
||||
struct video_frame *tx_frame;
|
||||
|
||||
struct video_frame *splitted_frames = NULL;
|
||||
struct tile_info t_info;
|
||||
int net_dev = 0;
|
||||
|
||||
if(uv->split_frames) {
|
||||
/* it is simply stripping frame */
|
||||
t_info.x_count = 1u;
|
||||
t_info.y_count = uv->connections_count;
|
||||
splitted_frames = (struct video_frame *)
|
||||
malloc(uv->connections_count *
|
||||
sizeof(struct video_frame));
|
||||
}
|
||||
|
||||
while (!should_exit) {
|
||||
/* Capture and transmit video... */
|
||||
tx_frame = vidcap_grab(uv->capture_device);
|
||||
@@ -493,9 +566,22 @@ static void *sender_thread(void *arg)
|
||||
compress_data(uv->compression, tx_frame);
|
||||
#endif /* HAVE_FASTDXT */
|
||||
}
|
||||
tx_send(uv->tx, tx_frame, uv->network_device);
|
||||
if(!uv->split_frames) {
|
||||
tx_send(uv->tx, tx_frame,
|
||||
uv->network_devices[net_dev]);
|
||||
net_dev = (net_dev + 1) % uv->connections_count;
|
||||
} else { /* split */
|
||||
int i;
|
||||
vf_split_horizontal(splitted_frames, tx_frame,
|
||||
t_info.y_count);
|
||||
for (i = 0; i < uv->connections_count; ++i) {
|
||||
tx_send(uv->tx, &splitted_frames[i],
|
||||
uv->network_devices[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
free(splitted_frames);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -524,6 +610,8 @@ int main(int argc, char *argv[])
|
||||
{"ihdtv", no_argument, 0, 'i'},
|
||||
{"receive", required_argument, 0, 'r'},
|
||||
{"send", required_argument, 0, 's'},
|
||||
{"split", no_argument, 0, 'S'},
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
int option_index = 0;
|
||||
@@ -544,14 +632,15 @@ int main(int argc, char *argv[])
|
||||
uv->audio_playback_device = -2;
|
||||
uv->audio_participants = NULL;
|
||||
uv->participants = NULL;
|
||||
uv->split_frames = 0;
|
||||
|
||||
#ifdef HAVE_AUDIO
|
||||
while ((ch =
|
||||
getopt_long(argc, argv, "d:g:t:m:f:b:r:s:vcpi", getopt_options,
|
||||
getopt_long(argc, argv, "d:g:t:m:f:b:r:s:vcpihS", getopt_options,
|
||||
&option_index)) != -1) {
|
||||
#else
|
||||
while ((ch =
|
||||
getopt_long(argc, argv, "d:g:t:m:f:b:vcpi", getopt_options,
|
||||
getopt_long(argc, argv, "d:g:t:m:f:b:vcpihS", getopt_options,
|
||||
&option_index)) != -1) {
|
||||
#endif /* HAVE_AUDIO */
|
||||
switch (ch) {
|
||||
@@ -616,6 +705,12 @@ int main(int argc, char *argv[])
|
||||
uv->audio_capture_device = atoi(optarg);
|
||||
break;
|
||||
#endif /* HAVE_AUDIO */
|
||||
case 'S':
|
||||
uv->split_frames = 1;
|
||||
break;
|
||||
case 'h':
|
||||
usage();
|
||||
return 0;
|
||||
case '?':
|
||||
break;
|
||||
default:
|
||||
@@ -703,14 +798,20 @@ int main(int argc, char *argv[])
|
||||
pthread_t audio_thread_id;
|
||||
if ((uv->audio_playback_device != -2)
|
||||
|| (uv->audio_capture_device != -2)) {
|
||||
uv->audio_participants = pdb_init();
|
||||
char *tmp;
|
||||
char *addr;
|
||||
tmp = strdup(argv[0]);
|
||||
uv->audio_participants = pdb_init();
|
||||
addr = strtok_r(tmp, NULL, NULL);
|
||||
if ((uv->audio_network_device =
|
||||
initialize_audio_network(argv[0],
|
||||
initialize_audio_network(addr,
|
||||
uv->audio_participants)) ==
|
||||
NULL) {
|
||||
printf("Unable to open audio network\n");
|
||||
free(tmp);
|
||||
return EXIT_FAIL_NETWORK;
|
||||
}
|
||||
free(tmp);
|
||||
|
||||
if (pthread_create
|
||||
(&audio_thread_id, NULL, audio_thread, (void *)uv) != 0) {
|
||||
@@ -794,10 +895,15 @@ int main(int argc, char *argv[])
|
||||
sleep(1);
|
||||
|
||||
} else {
|
||||
if ((uv->network_device =
|
||||
if ((uv->network_devices =
|
||||
initialize_network(argv[0], uv->participants)) == NULL) {
|
||||
printf("Unable to open network\n");
|
||||
return EXIT_FAIL_NETWORK;
|
||||
} else {
|
||||
struct rtp **item;
|
||||
uv->connections_count = 0;
|
||||
for(item = uv->network_devices; *item != NULL; ++item)
|
||||
++uv->connections_count;
|
||||
}
|
||||
|
||||
if (uv->requested_mtu == 0) // mtu wasn't specified on the command line
|
||||
@@ -841,7 +947,7 @@ int main(int argc, char *argv[])
|
||||
#endif /* HAVE_AUDIO */
|
||||
|
||||
tx_done(uv->tx);
|
||||
rtp_done(uv->network_device);
|
||||
destroy_devices(uv->network_devices);
|
||||
vidcap_done(uv->capture_device);
|
||||
display_done(uv->display_device);
|
||||
if (uv->participants != NULL)
|
||||
|
||||
@@ -58,6 +58,7 @@ void decode_frame(struct coded_data *cdata, struct video_frame *frame)
|
||||
uint32_t height;
|
||||
uint32_t offset;
|
||||
uint32_t aux;
|
||||
struct tile_info tile_info;
|
||||
int len;
|
||||
codec_t color_spec;
|
||||
rtp_packet *pckt;
|
||||
@@ -66,6 +67,7 @@ void decode_frame(struct coded_data *cdata, struct video_frame *frame)
|
||||
uint32_t data_pos;
|
||||
int prints=0;
|
||||
double fps;
|
||||
struct video_frame *tile;
|
||||
|
||||
if(!frame)
|
||||
return;
|
||||
@@ -80,20 +82,27 @@ void decode_frame(struct coded_data *cdata, struct video_frame *frame)
|
||||
data_pos = ntohl(hdr->offset);
|
||||
fps = ntohl(hdr->fps)/65536.0;
|
||||
aux = ntohl(hdr->aux);
|
||||
tile_info = ntoh_uint2tileinfo(hdr->tileinfo);
|
||||
|
||||
/* Critical section
|
||||
* each thread *MUST* wait here if this condition is true
|
||||
*/
|
||||
if (!(frame->width == width &&
|
||||
frame->height == height &&
|
||||
if (!(frame->width == (aux & AUX_TILED ? width * tile_info.x_count : width) &&
|
||||
frame->height == (aux & AUX_TILED ? height * tile_info.y_count : height) &&
|
||||
frame->color_spec == color_spec &&
|
||||
frame->aux == aux &&
|
||||
frame->fps == fps)) {
|
||||
frame->fps == fps &&
|
||||
(!(aux & AUX_TILED) || /* |- (tiled -> eq) <-> (!tiled OR eq) */
|
||||
tileinfo_eq_count(frame->tile_info, tile_info)))) {
|
||||
frame->reconfigure(frame->state, width, height,
|
||||
color_spec, fps, aux);
|
||||
color_spec, fps, aux, tile_info);
|
||||
frame->src_linesize =
|
||||
vc_getsrc_linesize(width, color_spec);
|
||||
vc_getsrc_linesize(frame->width, color_spec);
|
||||
}
|
||||
if (aux & AUX_TILED)
|
||||
tile = frame->get_tile_buffer(frame->state, tile_info);
|
||||
else
|
||||
tile = frame;
|
||||
/* End of critical section */
|
||||
|
||||
/* MAGIC, don't touch it, you definitely break it
|
||||
@@ -103,15 +112,16 @@ void decode_frame(struct coded_data *cdata, struct video_frame *frame)
|
||||
/* compute Y pos in source frame and convert it to
|
||||
* byte offset in the destination frame
|
||||
*/
|
||||
int y = (data_pos / frame->src_linesize) * frame->dst_pitch;
|
||||
int y = (data_pos / tile->src_linesize) * frame->dst_pitch;
|
||||
|
||||
/* compute X pos in source frame */
|
||||
int s_x = data_pos % frame->src_linesize;
|
||||
int s_x = data_pos % tile->src_linesize;
|
||||
|
||||
/* convert X pos from source frame into the destination frame.
|
||||
* it is byte offset from the beginning of a line.
|
||||
*/
|
||||
int d_x = ((int)((s_x) / frame->src_bpp)) * frame->dst_bpp;
|
||||
int d_x = tile->dst_x_offset + ((int)((s_x) / tile->src_bpp)) *
|
||||
frame->dst_bpp;
|
||||
|
||||
/* pointer to data payload in packet */
|
||||
source = (unsigned char*)(pckt->data + sizeof(payload_hdr_t));
|
||||
@@ -123,32 +133,32 @@ void decode_frame(struct coded_data *cdata, struct video_frame *frame)
|
||||
/* len id payload length in source BPP
|
||||
* decoder needs len in destination BPP, so convert it
|
||||
*/
|
||||
int l = ((int)(len / frame->src_bpp)) * frame->dst_bpp;
|
||||
int l = ((int)(len / tile->src_bpp)) * frame->dst_bpp;
|
||||
|
||||
/* do not copy multiple lines, we need to
|
||||
* copy (& clip, center) line by line
|
||||
*/
|
||||
if (l + d_x > (int)frame->dst_linesize) {
|
||||
l = frame->dst_linesize - d_x;
|
||||
if (l + d_x > (int)tile->dst_linesize) {
|
||||
l = tile->dst_linesize - d_x;
|
||||
}
|
||||
|
||||
/* compute byte offset in destination frame */
|
||||
offset = y + d_x;
|
||||
|
||||
/* watch the SEGV */
|
||||
if (l + offset <= frame->data_len) {
|
||||
if (l + offset <= tile->data_len) {
|
||||
/*decode frame:
|
||||
* we have offset for destination
|
||||
* we update source contiguously
|
||||
* we pass {r,g,b}shifts */
|
||||
frame->decoder((unsigned char*)frame->data + offset, source, l,
|
||||
frame->decoder((unsigned char*)tile->data + offset, source, l,
|
||||
frame->rshift, frame->gshift,
|
||||
frame->bshift);
|
||||
/* we decoded one line (or a part of one line) to the end of the line
|
||||
* so decrease *source* len by 1 line (or that part of the line */
|
||||
len -= frame->src_linesize - s_x;
|
||||
len -= tile->src_linesize - s_x;
|
||||
/* jump in source by the same amount */
|
||||
source += frame->src_linesize - s_x;
|
||||
source += tile->src_linesize - s_x;
|
||||
} else {
|
||||
/* this should not ever happen as we call reconfigure before each packet
|
||||
* iff reconfigure is needed. But if it still happens, something is terribly wrong
|
||||
@@ -162,7 +172,7 @@ void decode_frame(struct coded_data *cdata, struct video_frame *frame)
|
||||
len = 0;
|
||||
}
|
||||
/* each new line continues from the beginning */
|
||||
d_x = 0; /* next line from beginning */
|
||||
d_x = tile->dst_x_offset; /* next line from beginning */
|
||||
s_x = 0;
|
||||
y += frame->dst_pitch; /* next line */
|
||||
}
|
||||
|
||||
@@ -2155,6 +2155,48 @@ int rtp_recv(struct rtp *session, struct timeval *timeout, uint32_t curr_rtp_ts)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* rtp_recv_poll:
|
||||
* The meaning is as above with except that this function polls for first
|
||||
* nonempty stream and returns data.
|
||||
*
|
||||
* @param sessions null-terminated list of rtp sessions.
|
||||
* @param timeout timeout
|
||||
* @param cur_rtp_ts list null-terminated of timestamps for each session
|
||||
*/
|
||||
int rtp_recv_poll(struct rtp **sessions, struct timeval *timeout, uint32_t curr_rtp_ts)
|
||||
{
|
||||
struct rtp **current;
|
||||
|
||||
udp_fd_zero();
|
||||
|
||||
for(current = sessions; *current != NULL; ++current) {
|
||||
check_database(*current);
|
||||
udp_fd_set((*current)->rtp_socket);
|
||||
udp_fd_set((*current)->rtcp_socket);
|
||||
}
|
||||
if (udp_select(timeout) > 0) {
|
||||
for(current = sessions; *current != NULL; ++current) {
|
||||
if (udp_fd_isset((*current)->rtp_socket)) {
|
||||
rtp_recv_data(*current, curr_rtp_ts);
|
||||
}
|
||||
if (udp_fd_isset((*current)->rtcp_socket)) {
|
||||
uint8_t buffer[RTP_MAX_PACKET_LEN];
|
||||
int buflen;
|
||||
buflen =
|
||||
udp_recv((*current)->rtcp_socket, (char *)buffer,
|
||||
RTP_MAX_PACKET_LEN);
|
||||
ntp64_time(&tmp_sec, &tmp_frac);
|
||||
rtp_process_ctrl(*current, buffer, buflen);
|
||||
}
|
||||
check_database(*current);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
//check_database(session);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* rtp_add_csrc:
|
||||
* @session: the session pointer (returned by rtp_init())
|
||||
|
||||
@@ -222,6 +222,8 @@ int rtp_get_option(struct rtp *session, rtp_option optname, int *optval);
|
||||
|
||||
int rtp_recv(struct rtp *session,
|
||||
struct timeval *timeout, uint32_t curr_rtp_ts);
|
||||
int rtp_recv_poll(struct rtp **sessions,
|
||||
struct timeval *timeout, uint32_t curr_rtp_ts);
|
||||
|
||||
int rtp_send_data(struct rtp *session,
|
||||
uint32_t rtp_ts, char pt, int m,
|
||||
|
||||
@@ -59,6 +59,7 @@ typedef struct {
|
||||
uint8_t flags;
|
||||
uint32_t fps; /* fixed point fps. take care! */
|
||||
uint32_t aux; /* auxiliary data */
|
||||
uint32_t tileinfo; /* info about tile position (if tiled) */
|
||||
} payload_hdr_t;
|
||||
|
||||
/* FIXME: this is only needed because fdisplay() takes "struct display" as a parameter */
|
||||
|
||||
179
ultragrid/src/tile.c
Normal file
179
ultragrid/src/tile.c
Normal file
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
* FILE: tile.c
|
||||
* AUTHORS: Martin Benes <martinbenesh@gmail.com>
|
||||
* Lukas Hejtmanek <xhejtman@ics.muni.cz>
|
||||
* Petr Holub <hopet@ics.muni.cz>
|
||||
* Milos Liska <xliska@fi.muni.cz>
|
||||
* Jiri Matela <matela@ics.muni.cz>
|
||||
* Dalibor Matura <255899@mail.muni.cz>
|
||||
* Ian Wesley-Smith <iwsmith@cct.lsu.edu>
|
||||
*
|
||||
* Copyright (c) 2005-2010 CESNET z.s.p.o.
|
||||
*
|
||||
* 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
|
||||
* 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 <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "video_codec.h"
|
||||
#include "tile.h"
|
||||
|
||||
#define MAGIC_H 0xFF
|
||||
#define MAGIC_T 0xFE
|
||||
|
||||
void vf_split(struct video_frame *out, struct video_frame *src,
|
||||
unsigned int x_count, unsigned int y_count, int preallocate)
|
||||
{
|
||||
unsigned int tile_idx, line_idx;
|
||||
struct video_frame *cur_tiles;
|
||||
unsigned int tile_line;
|
||||
|
||||
assert(src->width % x_count == 0u && src->height % y_count == 0u);
|
||||
|
||||
for(tile_idx = 0u; tile_idx < x_count * y_count; ++tile_idx) {
|
||||
out[tile_idx].width = src->width / x_count;
|
||||
out[tile_idx].height = src->height / y_count;
|
||||
out[tile_idx].color_spec = src->color_spec;
|
||||
out[tile_idx].aux = src->aux | AUX_TILED;
|
||||
out[tile_idx].fps = src->fps;
|
||||
out[tile_idx].tile_info.x_count = x_count;
|
||||
out[tile_idx].tile_info.y_count = y_count;
|
||||
out[tile_idx].tile_info.pos_x = tile_idx % x_count;
|
||||
out[tile_idx].tile_info.pos_y = tile_idx / x_count;
|
||||
out[tile_idx].src_linesize = vc_getsrc_linesize(out[tile_idx].width,
|
||||
src->color_spec);
|
||||
out[tile_idx].data_len = out[tile_idx].src_linesize * out[tile_idx].height;
|
||||
}
|
||||
|
||||
cur_tiles = out;
|
||||
for(line_idx = 0u; line_idx < src->height; ++line_idx, ++tile_line) {
|
||||
unsigned int cur_tile_idx;
|
||||
unsigned int byte = 0u;
|
||||
|
||||
if (line_idx % (src->height / y_count) == 0u) /* next tiles*/
|
||||
{
|
||||
tile_line = 0u;
|
||||
if (line_idx != 0u)
|
||||
cur_tiles += x_count;
|
||||
if (preallocate) {
|
||||
for (cur_tile_idx = 0u; cur_tile_idx < x_count;
|
||||
++cur_tile_idx) {
|
||||
cur_tiles[cur_tile_idx].data =
|
||||
malloc(cur_tiles[cur_tile_idx].
|
||||
data_len);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(cur_tile_idx = 0u; cur_tile_idx < x_count; ++cur_tile_idx) {
|
||||
memcpy((void *) &cur_tiles[cur_tile_idx].data[
|
||||
tile_line *
|
||||
cur_tiles[cur_tile_idx].src_linesize],
|
||||
(void *) &src->data[line_idx *
|
||||
src->src_linesize + byte],
|
||||
cur_tiles[cur_tile_idx].width *
|
||||
get_bpp(src->color_spec));
|
||||
byte += cur_tiles[cur_tile_idx].width * get_bpp(src->color_spec);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void vf_split_horizontal(struct video_frame *out, struct video_frame *src,
|
||||
unsigned int y_count)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for(i = 0u; i < y_count; ++i) {
|
||||
out[i].width = src->width;
|
||||
out[i].height = src->height / y_count;
|
||||
out[i].color_spec = src->color_spec;
|
||||
out[i].aux = src->aux | AUX_TILED;
|
||||
out[i].fps = src->fps;
|
||||
out[i].tile_info.x_count = 1u;
|
||||
out[i].tile_info.y_count = y_count;
|
||||
out[i].tile_info.pos_x = 0u;
|
||||
out[i].tile_info.pos_y = i;
|
||||
out[i].src_linesize = vc_getsrc_linesize(out[i].width,
|
||||
src->color_spec);
|
||||
out[i].data_len = out[i].src_linesize * out[i].height;
|
||||
out[i].data = src->data + i * out[i].height * src->src_linesize;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t hton_tileinfo2uint(struct tile_info tile_info)
|
||||
{
|
||||
union {
|
||||
struct tile_info t_info;
|
||||
uint32_t res;
|
||||
} trans;
|
||||
trans.t_info = tile_info;
|
||||
trans.t_info.h_reserved = MAGIC_H;
|
||||
trans.t_info.t_reserved = MAGIC_T;
|
||||
return htonl(trans.res);
|
||||
}
|
||||
|
||||
struct tile_info ntoh_uint2tileinfo(uint32_t packed)
|
||||
{
|
||||
union {
|
||||
struct tile_info t_info;
|
||||
uint32_t src;
|
||||
} trans;
|
||||
trans.src = ntohl(packed);
|
||||
if(trans.t_info.h_reserved = MAGIC_H)
|
||||
return trans.t_info;
|
||||
else { /* == MAGIC_T */
|
||||
int tmp;
|
||||
tmp = trans.t_info.x_count << 4u & trans.t_info.y_count;
|
||||
trans.t_info.x_count = trans.t_info.pos_x;
|
||||
trans.t_info.y_count = trans.t_info.pos_y;
|
||||
trans.t_info.pos_x = tmp >> 4u;
|
||||
trans.t_info.pos_y = tmp & 0xF;
|
||||
return trans.t_info;
|
||||
}
|
||||
}
|
||||
|
||||
int tileinfo_eq_count(struct tile_info t1, struct tile_info t2)
|
||||
{
|
||||
return t1.x_count == t2.x_count && t1.y_count == t2.y_count;
|
||||
}
|
||||
|
||||
100
ultragrid/src/tile.h
Normal file
100
ultragrid/src/tile.h
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* FILE: tile.h
|
||||
* AUTHORS: Martin Benes <martinbenesh@gmail.com>
|
||||
* Lukas Hejtmanek <xhejtman@ics.muni.cz>
|
||||
* Petr Holub <hopet@ics.muni.cz>
|
||||
* Milos Liska <xliska@fi.muni.cz>
|
||||
* Jiri Matela <matela@ics.muni.cz>
|
||||
* Dalibor Matura <255899@mail.muni.cz>
|
||||
* Ian Wesley-Smith <iwsmith@cct.lsu.edu>
|
||||
*
|
||||
* Copyright (c) 2005-2010 CESNET z.s.p.o.
|
||||
*
|
||||
* 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
|
||||
* 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 __tile_h
|
||||
|
||||
#define __tile_h
|
||||
|
||||
struct video_frame;
|
||||
struct codec_info_t;
|
||||
enum codec_t;
|
||||
|
||||
struct tile_info {
|
||||
unsigned int h_reserved:8;
|
||||
unsigned int pos_x:4;
|
||||
unsigned int pos_y:4;
|
||||
unsigned int x_count:4;
|
||||
unsigned int y_count:4;
|
||||
unsigned int t_reserved:8;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
/**
|
||||
* vf_split splits the frame into multiple tiles.
|
||||
* Caller is responsible for allocating memory for all of these: out (to hold
|
||||
* all elements), out elements and theirs data member to hold tile data.
|
||||
*
|
||||
* width must be divisible by x_count && heigth by y_count (!)
|
||||
*
|
||||
* @param out output video frames array
|
||||
* the resulting matrix will be stored row-dominant
|
||||
* @param src source video frame
|
||||
* @param x_count number of columns
|
||||
* @param y_count number of rows
|
||||
* @param preallocate used for preallocating buffers because determining right
|
||||
* size can be cumbersome. Anyway only .data are allocated.
|
||||
*/
|
||||
void vf_split(struct video_frame *out, struct video_frame *src,
|
||||
unsigned int x_count, unsigned int y_count, int preallocate);
|
||||
|
||||
void vf_split_horizontal(struct video_frame *out, struct video_frame *src,
|
||||
unsigned int y_count);
|
||||
|
||||
|
||||
uint32_t hton_tileinfo2uint(struct tile_info tile_info);
|
||||
struct tile_info ntoh_uint2tileinfo(uint32_t packed);
|
||||
|
||||
/**
|
||||
* tileinfo_eq:
|
||||
* compares count of tiles
|
||||
*
|
||||
* @param t1 first structure
|
||||
* @param t2 second structure
|
||||
* @return 0 if different
|
||||
* !0 if equal
|
||||
*/
|
||||
int tileinfo_eq_count(struct tile_info t1, struct tile_info t2);
|
||||
|
||||
#endif
|
||||
@@ -129,6 +129,7 @@ tx_send(struct video_tx *tx, struct video_frame *frame, struct rtp *rtp_session)
|
||||
payload_hdr.colorspc = frame->color_spec;
|
||||
payload_hdr.fps = htonl((int)(frame->fps * 65536));
|
||||
payload_hdr.aux = htonl(frame->aux);
|
||||
payload_hdr.tileinfo = hton_tileinfo2uint(frame->tile_info);
|
||||
|
||||
do {
|
||||
payload_hdr.offset = htonl(pos);
|
||||
|
||||
@@ -79,6 +79,8 @@ struct testcard_state {
|
||||
SDL_Surface *surface;
|
||||
struct timeval t0;
|
||||
struct video_frame frame;
|
||||
struct video_frame *tiles;
|
||||
int last_tile_sent;
|
||||
};
|
||||
|
||||
const int rect_colors[] = {
|
||||
@@ -255,10 +257,37 @@ void toR10k(unsigned char *in, unsigned int width, unsigned int height)
|
||||
}
|
||||
}
|
||||
|
||||
static int configure_tiling(struct testcard_state *s, const char *fmt)
|
||||
{
|
||||
char *tmp, *token, *saveptr;
|
||||
|
||||
if(fmt[1] != '=') return 1;
|
||||
s->frame.aux |= AUX_TILED;
|
||||
tmp = strdup(&fmt[2]);
|
||||
token = strtok_r(tmp, "x", &saveptr);
|
||||
s->frame.tile_info.x_count = atoi(token);
|
||||
token = strtok_r(NULL, "x", &saveptr);
|
||||
s->frame.tile_info.y_count = atoi(token);
|
||||
free(tmp);
|
||||
if(s->frame.tile_info.x_count < 1u ||
|
||||
s->frame.tile_info.y_count < 1u) {
|
||||
fprintf(stderr, "There must be at least 1x1 tile.\n");
|
||||
return 1;
|
||||
}
|
||||
s->tiles = (struct video_frame *)
|
||||
malloc(s->frame.tile_info.x_count *
|
||||
s->frame.tile_info.y_count *
|
||||
sizeof(struct video_frame));
|
||||
vf_split(s->tiles, &s->frame, s->frame.tile_info.x_count,
|
||||
s->frame.tile_info.y_count, 1); /*prealloc*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *vidcap_testcard_init(char *fmt)
|
||||
{
|
||||
struct testcard_state *s;
|
||||
char *filename;
|
||||
const char *strip_fmt = NULL;
|
||||
FILE *in;
|
||||
struct stat sb;
|
||||
unsigned int i, j;
|
||||
@@ -268,8 +297,9 @@ void *vidcap_testcard_init(char *fmt)
|
||||
|
||||
if (strcmp(fmt, "help") == 0) {
|
||||
printf("testcard options:\n");
|
||||
printf("\twidth:height:fps:codec[:filename][:p}\n");
|
||||
printf("\twidth:height:fps:codec[:filename][:p][:s=XxY]\n");
|
||||
printf("\tp - pan with frame\n");
|
||||
printf("\ts - split the frames into XxY separate tiles\n");
|
||||
show_codec_help("testcard");
|
||||
return NULL;
|
||||
}
|
||||
@@ -341,7 +371,8 @@ void *vidcap_testcard_init(char *fmt)
|
||||
s->size = aligned_x * s->frame.height * bpp;
|
||||
|
||||
filename = strtok(NULL, ":");
|
||||
if (filename && strcmp(filename, "p") != 0) {
|
||||
if (filename && strcmp(filename, "p") != 0
|
||||
&& strncmp(filename, "s=", 2ul) != 0) {
|
||||
s->frame.data = malloc(s->size);
|
||||
if (stat(filename, &sb)) {
|
||||
perror("stat");
|
||||
@@ -375,8 +406,11 @@ void *vidcap_testcard_init(char *fmt)
|
||||
SDL_CreateRGBSurface(SDL_SWSURFACE, aligned_x, s->frame.height,
|
||||
32, 0xff, 0xff00, 0xff0000,
|
||||
0xff000000);
|
||||
if (filename && filename[0] == 'p') {
|
||||
s->pan = 48;
|
||||
if (filename) {
|
||||
if(filename[0] == 'p')
|
||||
s->pan = 48;
|
||||
else if(filename[0] == 's')
|
||||
strip_fmt = filename;
|
||||
}
|
||||
|
||||
for (j = 0; j < s->frame.height; j += rect_size) {
|
||||
@@ -429,6 +463,14 @@ void *vidcap_testcard_init(char *fmt)
|
||||
if (tmp) {
|
||||
if (tmp[0] == 'p') {
|
||||
s->pan = 48;
|
||||
} else if (tmp[0] == 's') {
|
||||
strip_fmt = tmp;
|
||||
}
|
||||
}
|
||||
tmp = strtok(NULL, ":");
|
||||
if (tmp) {
|
||||
if (tmp[0] == 's') {
|
||||
strip_fmt = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -440,6 +482,13 @@ void *vidcap_testcard_init(char *fmt)
|
||||
s->frame.state = s;
|
||||
s->frame.data_len = s->size;
|
||||
|
||||
if(strip_fmt != NULL) {
|
||||
if(configure_tiling(s, strip_fmt) != 0)
|
||||
return NULL;
|
||||
} else {
|
||||
s->frame.aux &= ~AUX_TILED;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -450,6 +499,14 @@ void vidcap_testcard_done(void *state)
|
||||
free(s->frame.data);
|
||||
if (s->surface)
|
||||
SDL_FreeSurface(s->surface);
|
||||
if (s->frame.aux & AUX_TILED)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0u; i < s->frame.tile_info.x_count *
|
||||
s->frame.tile_info.y_count; ++i)
|
||||
free(s->tiles[i].data);
|
||||
free(s->tiles);
|
||||
}
|
||||
free(s);
|
||||
}
|
||||
|
||||
@@ -460,6 +517,12 @@ struct video_frame *vidcap_testcard_grab(void *arg)
|
||||
|
||||
state = (struct testcard_state *)arg;
|
||||
|
||||
if (state->frame.aux & AUX_TILED) {
|
||||
if (state->last_tile_sent < state->tiles->tile_info.x_count *
|
||||
state->tiles->tile_info.y_count - 1)
|
||||
return &state->tiles[++state->last_tile_sent];
|
||||
}
|
||||
|
||||
gettimeofday(&curr_time, NULL);
|
||||
if (tv_diff(curr_time, state->last_frame_time) >
|
||||
1.0 / (double)state->frame.fps) {
|
||||
@@ -499,6 +562,16 @@ struct video_frame *vidcap_testcard_grab(void *arg)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (state->frame.aux & AUX_TILED && state->last_tile_sent ==
|
||||
state->tiles->tile_info.x_count *
|
||||
state->tiles->tile_info.y_count
|
||||
- 1) {
|
||||
vf_split(state->tiles, &state->frame,
|
||||
state->frame.tile_info.x_count,
|
||||
state->frame.tile_info.y_count, 0);
|
||||
state->last_tile_sent = 0;
|
||||
return state->tiles;
|
||||
}
|
||||
return &state->frame;
|
||||
}
|
||||
return NULL;
|
||||
|
||||
@@ -55,11 +55,11 @@
|
||||
#include "video_codec.h"
|
||||
|
||||
const struct codec_info_t codec_info[] = {
|
||||
{RGBA, "RGBA", 0, 0, 4.0, 1},
|
||||
{UYVY, "UYVY", 846624121, 0, 2, 0},
|
||||
{Vuy2, "2vuy", '2vuy', 0, 2, 0},
|
||||
{DVS8, "DVS8", 0, 0, 2, 0},
|
||||
{R10k, "R10k", 1378955371, 0, 4, 1},
|
||||
{RGBA, "RGBA", 0, 1, 4.0, 1},
|
||||
{UYVY, "UYVY", 846624121, 1, 2, 0},
|
||||
{Vuy2, "2vuy", '2vuy', 1, 2, 0},
|
||||
{DVS8, "DVS8", 0, 1, 2, 0},
|
||||
{R10k, "R10k", 1378955371, 1, 4, 1},
|
||||
{v210, "v210", 1983000880, 48, 8.0 / 3.0, 0},
|
||||
{DVS10, "DVS10", 0, 48, 8.0 / 3.0, 0},
|
||||
{0, NULL, 0, 0, 0.0, 0}
|
||||
@@ -406,3 +406,4 @@ void vc_copylineDVS10(unsigned char *dst, unsigned char *src, int src_len)
|
||||
}
|
||||
|
||||
#endif /* !(HAVE_MACOSX || HAVE_32B_LINUX) */
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
#ifndef __video_codec_h
|
||||
|
||||
#define __video_codec_h
|
||||
#include "tile.h"
|
||||
|
||||
typedef enum {
|
||||
RGBA,
|
||||
@@ -59,7 +60,11 @@ typedef enum {
|
||||
} codec_t;
|
||||
|
||||
typedef void (*decoder_t)(unsigned char *dst, unsigned char *src, int dst_len, int rshift, int gshift, int bshift);
|
||||
typedef void (*reconfigure_t)(void *state, int width, int height, codec_t color_spec, double fps, int aux);
|
||||
typedef void (*reconfigure_t)(void *state, int width, int height, codec_t color_spec, double fps, int aux, struct tile_info tileinfo);
|
||||
/**
|
||||
* function of this type should return buffer corresponding to the given tile_info struct
|
||||
*/
|
||||
typedef struct video_frame * (*get_tile_buffer_t)(void *state, struct tile_info tile_info);
|
||||
|
||||
|
||||
struct video_frame {
|
||||
@@ -74,7 +79,7 @@ struct video_frame {
|
||||
unsigned int dst_linesize; /* framebuffer pitch */
|
||||
unsigned int dst_pitch; /* framebuffer pitch - it can be larger if SDL resolution is larger than data */
|
||||
unsigned int src_linesize; /* display data pitch */
|
||||
unsigned int dst_x_offset; /* X offset in frame buffer */
|
||||
unsigned int dst_x_offset; /* X offset in frame buffer in bytes */
|
||||
double src_bpp;
|
||||
double dst_bpp;
|
||||
int rshift;
|
||||
@@ -82,9 +87,11 @@ struct video_frame {
|
||||
int bshift;
|
||||
decoder_t decoder;
|
||||
reconfigure_t reconfigure;
|
||||
get_tile_buffer_t get_tile_buffer;
|
||||
void *state;
|
||||
double fps;
|
||||
int aux;
|
||||
struct tile_info tile_info;
|
||||
};
|
||||
|
||||
|
||||
@@ -117,6 +124,7 @@ void vc_copylineDVS10toV210(unsigned char *dst, unsigned char *src, int dst_len)
|
||||
#define AUX_RGB 1<<3 /* if device supports both, set both */
|
||||
#define AUX_YUV 1<<4
|
||||
#define AUX_10Bit 1<<5
|
||||
|
||||
#define AUX_TILED 1<<6
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -96,6 +96,7 @@ struct state_sdl {
|
||||
SDL_Overlay *yuv_image;
|
||||
SDL_Surface *rgb_image;
|
||||
struct video_frame frame;
|
||||
struct video_frame *tiles;
|
||||
|
||||
pthread_t thread_id;
|
||||
SDL_sem *semaphore;
|
||||
@@ -127,7 +128,8 @@ void deinterlace(struct state_sdl *s, unsigned char *buffer);
|
||||
static void show_help(void);
|
||||
void cleanup_screen(struct state_sdl *s);
|
||||
void reconfigure_screen(void *s, unsigned int width, unsigned int height,
|
||||
codec_t codec, double fps, int aux);
|
||||
codec_t codec, double fps, int aux, struct tile_info tile_info);
|
||||
static struct video_frame * get_tile_buffer(void *s, struct tile_info tile_info);
|
||||
|
||||
extern int should_exit;
|
||||
|
||||
@@ -247,11 +249,15 @@ static void loadSplashscreen(struct state_sdl *s) {
|
||||
static void toggleFullscreen(struct state_sdl *s) {
|
||||
if(s->fs) {
|
||||
s->fs = 0;
|
||||
reconfigure_screen(s, s->frame.width, s->frame.height, s->codec_info->codec, s->frame.fps, s->frame.aux);
|
||||
reconfigure_screen(s, s->frame.width, s->frame.height,
|
||||
s->codec_info->codec, s->frame.fps,
|
||||
s->frame.aux, s->frame.tile_info);
|
||||
}
|
||||
else {
|
||||
s->fs = 1;
|
||||
reconfigure_screen(s, s->frame.width, s->frame.height, s->codec_info->codec, s->frame.fps, s->frame.aux);
|
||||
reconfigure_screen(s, s->frame.width, s->frame.height,
|
||||
s->codec_info->codec, s->frame.fps,
|
||||
s->frame.aux, s->frame.tile_info);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -369,7 +375,8 @@ void cleanup_screen(struct state_sdl *s)
|
||||
|
||||
void
|
||||
reconfigure_screen(void *state, unsigned int width, unsigned int height,
|
||||
codec_t color_spec, double fps, int aux)
|
||||
codec_t color_spec, double fps, int aux,
|
||||
struct tile_info tile_info)
|
||||
{
|
||||
struct state_sdl *s = (struct state_sdl *)state;
|
||||
int itemp;
|
||||
@@ -383,13 +390,19 @@ reconfigure_screen(void *state, unsigned int width, unsigned int height,
|
||||
|
||||
cleanup_screen(s);
|
||||
|
||||
fprintf(stdout, "Reconfigure to size %dx%d\n", width, height);
|
||||
|
||||
s->frame.width = width;
|
||||
s->frame.height = height;
|
||||
if (aux & AUX_TILED) {
|
||||
s->frame.width = width * tile_info.x_count;
|
||||
s->frame.height = height * tile_info.y_count;
|
||||
} else {
|
||||
s->frame.width = width;
|
||||
s->frame.height = height;
|
||||
}
|
||||
s->frame.fps = fps;
|
||||
s->frame.aux = aux;
|
||||
|
||||
fprintf(stdout, "Reconfigure to size %dx%d\n", s->frame.width,
|
||||
s->frame.height);
|
||||
|
||||
ret =
|
||||
XGetGeometry(s->display, DefaultRootWindow(s->display), &wtemp,
|
||||
&itemp, &itemp, &x_res_x, &x_res_y, &utemp, &utemp);
|
||||
@@ -478,10 +491,10 @@ reconfigure_screen(void *state, unsigned int width, unsigned int height,
|
||||
(int) s->sdl_screen->pitch * x_res_y -
|
||||
s->sdl_screen->pitch * s->dst_rect.y +
|
||||
s->dst_rect.x * s->sdl_screen->format->BytesPerPixel;
|
||||
s->frame.dst_x_offset =
|
||||
s->dst_rect.x * s->sdl_screen->format->BytesPerPixel;
|
||||
s->frame.dst_bpp = s->sdl_screen->format->BytesPerPixel;
|
||||
s->frame.dst_pitch = s->sdl_screen->pitch;
|
||||
s->frame.dst_x_offset =
|
||||
s->dst_rect.x * s->sdl_screen->format->BytesPerPixel;
|
||||
s->frame.dst_bpp = s->sdl_screen->format->BytesPerPixel;
|
||||
s->frame.dst_pitch = s->sdl_screen->pitch;
|
||||
} else {
|
||||
s->frame.data = (char *)*s->yuv_image->pixels;
|
||||
s->frame.data_len = s->frame.width * s->frame.height * 2;
|
||||
@@ -509,14 +522,54 @@ reconfigure_screen(void *state, unsigned int width, unsigned int height,
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (s->tiles != NULL) {
|
||||
free(s->tiles);
|
||||
s->tiles = NULL;
|
||||
}
|
||||
if (aux & AUX_TILED) {
|
||||
int x, y;
|
||||
const int x_cnt = tile_info.x_count;
|
||||
|
||||
s->frame.tile_info = tile_info;
|
||||
s->tiles = (struct video_frame *)
|
||||
malloc(s->frame.tile_info.x_count *
|
||||
s->frame.tile_info.y_count *
|
||||
sizeof(struct video_frame));
|
||||
for (y = 0; y < s->frame.tile_info.y_count; ++y)
|
||||
for(x = 0; x < s->frame.tile_info.x_count; ++x) {
|
||||
memcpy(&s->tiles[y*x_cnt + x], &s->frame,
|
||||
sizeof(struct video_frame));
|
||||
s->tiles[y*x_cnt + x].width = width;
|
||||
s->tiles[y*x_cnt + x].height = height;
|
||||
s->tiles[y*x_cnt + x].tile_info.pos_x = x;
|
||||
s->tiles[y*x_cnt + x].tile_info.pos_y = y;
|
||||
s->tiles[y*x_cnt + x].dst_x_offset +=
|
||||
x * width * (s->rgb ? 4 : 2 /*vuy2*/);
|
||||
s->tiles[y*x_cnt + x].data +=
|
||||
y * height * s->frame.dst_pitch;
|
||||
s->tiles[y*x_cnt + x].src_linesize =
|
||||
vc_getsrc_linesize(width, color_spec);
|
||||
s->tiles[y*x_cnt + x].dst_linesize =
|
||||
vc_getsrc_linesize((x + 1) * width, color_spec);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static struct video_frame * get_tile_buffer(void *state, struct tile_info tile_info) {
|
||||
struct state_sdl *s = (struct state_sdl *)state;
|
||||
|
||||
assert(s->tiles != NULL); /* basic sanity test... */
|
||||
return &s->tiles[tile_info.pos_x + tile_info.pos_y * tile_info.x_count];
|
||||
}
|
||||
|
||||
void *display_sdl_init(char *fmt)
|
||||
{
|
||||
struct state_sdl *s;
|
||||
int ret;
|
||||
struct state_sdl *s;
|
||||
int ret;
|
||||
|
||||
unsigned int i;
|
||||
unsigned int i;
|
||||
|
||||
s = (struct state_sdl *)calloc(1, sizeof(struct state_sdl));
|
||||
s->magic = MAGIC_SDL;
|
||||
@@ -617,13 +670,18 @@ void *display_sdl_init(char *fmt)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s->frame.aux &= ~AUX_TILED; /* do not expect tiled video by default */
|
||||
s->tiles = NULL;
|
||||
if (fmt != NULL) {
|
||||
reconfigure_screen(s, s->frame.width, s->frame.height, s->codec_info->codec, s->frame.fps, s->frame.aux);
|
||||
reconfigure_screen(s, s->frame.width, s->frame.height,
|
||||
s->codec_info->codec, s->frame.fps,
|
||||
s->frame.aux, s->frame.tile_info);
|
||||
loadSplashscreen(s);
|
||||
}
|
||||
|
||||
s->frame.state = s;
|
||||
s->frame.reconfigure = (reconfigure_t)reconfigure_screen;
|
||||
s->frame.get_tile_buffer = (get_tile_buffer_t) get_tile_buffer;
|
||||
|
||||
if (pthread_create(&(s->thread_id), NULL,
|
||||
display_thread_sdl, (void *)s) != 0) {
|
||||
@@ -640,6 +698,8 @@ void display_sdl_done(void *state)
|
||||
|
||||
assert(s->magic == MAGIC_SDL);
|
||||
|
||||
if(s->tiles != NULL)
|
||||
free(s->tiles);
|
||||
/*FIXME: free all the stuff */
|
||||
SDL_ShowCursor(SDL_ENABLE);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user