Skip to content

Commit

Permalink
Improve and fix the upload of video data to textures.
Browse files Browse the repository at this point in the history
The new version only copies the required data, not more. Also, it avoids
reading beyond buffer boundaries for the even-odd-row input mode.
  • Loading branch information
marlam committed Dec 19, 2010
1 parent a7956ce commit 795897c
Show file tree
Hide file tree
Showing 11 changed files with 195 additions and 159 deletions.
13 changes: 13 additions & 0 deletions src/decoder.cpp
Expand Up @@ -42,6 +42,19 @@ std::string decoder::video_frame_format_name(enum video_frame_format f)
} }
} }


int decoder::video_frame_format_planes(enum video_frame_format f)
{
switch (f)
{
case frame_format_yuv420p:
return 3;
break;
case frame_format_bgra32:
return 1;
break;
}
}

std::string decoder::audio_sample_format_name(enum audio_sample_format f) std::string decoder::audio_sample_format_name(enum audio_sample_format f)
{ {
switch (f) switch (f)
Expand Down
1 change: 1 addition & 0 deletions src/decoder.h
Expand Up @@ -42,6 +42,7 @@ class decoder
}; };


static std::string video_frame_format_name(enum video_frame_format f); static std::string video_frame_format_name(enum video_frame_format f);
static int video_frame_format_planes(enum video_frame_format f);


/* The audio sample format */ /* The audio sample format */


Expand Down
147 changes: 73 additions & 74 deletions src/input.cpp
Expand Up @@ -22,6 +22,7 @@
#include "config.h" #include "config.h"


#include <cctype> #include <cctype>
#include <cstdlib>


#include "debug.h" #include "debug.h"
#include "exc.h" #include "exc.h"
Expand Down Expand Up @@ -472,101 +473,99 @@ int64_t input::read_video_frame()
return t; return t;
} }


void input::get_video_frame(enum decoder::video_frame_format fmt, void input::prepare_video_frame()
uint8_t *l_data[3], size_t l_line_size[3],
uint8_t *r_data[3], size_t r_line_size[3])
{ {
uint8_t *data[3], *data1[3]; _decoders.at(_video_decoders[0])->get_video_frame(_video_streams[0], video_frame_format(),
size_t line_size[3], line_size1[3]; _video_data[0], _video_data_line_size[0]);
if (_mode == separate)
{
_decoders.at(_video_decoders[1])->get_video_frame(_video_streams[1], video_frame_format(),
_video_data[1], _video_data_line_size[1]);
}
}

static int next_multiple_of_4(int x)
{
return (x / 4 + (x % 4 == 0 ? 0 : 1)) * 4;
}

void input::get_video_frame(int view, int plane, void *buf)
{
if (_swap_eyes)
{
view = (view == 0 ? 1 : 0);
}

uint8_t *dst = reinterpret_cast<uint8_t *>(buf);
uint8_t *src;
size_t src_offset;
size_t src_row_size;
size_t dst_row_width;
size_t dst_row_size;
size_t height;

if (video_frame_format() == decoder::frame_format_yuv420p)
{
if (plane == 0)
{
dst_row_width = video_width();
dst_row_size = next_multiple_of_4(dst_row_width);
height = video_height();
}
else
{
dst_row_width = video_width() / 2;
dst_row_size = next_multiple_of_4(dst_row_width);
height = video_height() / 2;
}
}
else
{
dst_row_width = video_width() * 4;
dst_row_size = dst_row_width;
height = video_height();
}


_decoders.at(_video_decoders[0])->get_video_frame(_video_streams[0], fmt, data, line_size);
switch (_mode) switch (_mode)
{ {
case separate: case separate:
_decoders.at(_video_decoders[1])->get_video_frame(_video_streams[1], fmt, data1, line_size1); src = _video_data[view][plane];
l_data[0] = data[0]; src_row_size = _video_data_line_size[view][plane];
l_data[1] = data[1]; src_offset = 0;
l_data[2] = data[2];
l_line_size[0] = line_size[0];
l_line_size[1] = line_size[1];
l_line_size[2] = line_size[2];
r_data[0] = data1[0];
r_data[1] = data1[1];
r_data[2] = data1[2];
r_line_size[0] = line_size1[0];
r_line_size[1] = line_size1[1];
r_line_size[2] = line_size1[2];
break; break;
case top_bottom: case top_bottom:
case top_bottom_half: case top_bottom_half:
l_data[0] = data[0]; src = _video_data[0][plane];
l_data[1] = data[1]; src_row_size = _video_data_line_size[0][plane];
l_data[2] = data[2]; src_offset = view * height * src_row_size;
l_line_size[0] = line_size[0];
l_line_size[1] = line_size[1];
l_line_size[2] = line_size[2];
r_data[0] = l_data[0] + video_height() * line_size[0];
r_data[1] = l_data[1] + video_height() / 2 * line_size[1];
r_data[2] = l_data[2] + video_height() / 2 * line_size[2];
r_line_size[0] = l_line_size[0];
r_line_size[1] = l_line_size[1];
r_line_size[2] = l_line_size[2];
break; break;
case left_right: case left_right:
case left_right_half: case left_right_half:
l_data[0] = data[0]; src = _video_data[0][plane];
l_data[1] = data[1]; src_row_size = _video_data_line_size[0][plane];
l_data[2] = data[2]; src_offset = view * dst_row_width;
l_line_size[0] = line_size[0];
l_line_size[1] = line_size[1];
l_line_size[2] = line_size[2];
r_data[0] = data[0] + video_width() * (fmt == decoder::frame_format_yuv420p ? 1 : 4);
r_data[1] = data[1] + video_width() / 2; // irrelevant for bgra32
r_data[2] = data[2] + video_width() / 2; // irrelevant for bgra32
r_line_size[0] = line_size[0];
r_line_size[1] = line_size[1];
r_line_size[2] = line_size[2];
break; break;
case even_odd_rows: case even_odd_rows:
l_data[0] = data[0]; src = _video_data[0][plane];
l_data[1] = data[1]; src_row_size = 2 * _video_data_line_size[0][plane];
l_data[2] = data[2]; src_offset = view * _video_data_line_size[0][plane];
l_line_size[0] = 2 * line_size[0];
l_line_size[1] = 2 * line_size[1];
l_line_size[2] = 2 * line_size[2];
r_data[0] = data[0] + line_size[0];
r_data[1] = data[1] + line_size[1];
r_data[2] = data[2] + line_size[2];
r_line_size[0] = 2 * line_size[0];
r_line_size[1] = 2 * line_size[1];
r_line_size[2] = 2 * line_size[2];
break; break;
case mono: case mono:
l_data[0] = data[0]; src = _video_data[0][plane];
l_data[1] = data[1]; src_row_size = _video_data_line_size[0][plane];
l_data[2] = data[2]; src_offset = 0;
l_line_size[0] = line_size[0];
l_line_size[1] = line_size[1];
l_line_size[2] = line_size[2];
r_data[0] = data[0];
r_data[1] = data[1];
r_data[2] = data[2];
r_line_size[0] = line_size[0];
r_line_size[1] = line_size[1];
r_line_size[2] = line_size[2];
break; break;
case automatic: case automatic:
/* cannot happen */ /* cannot happen */
break; break;
} }
if (_swap_eyes)
size_t dst_offset = 0;
for (size_t y = 0; y < height; y++)
{ {
std::swap(l_data[0], r_data[0]); std::memcpy(dst + dst_offset, src + src_offset, dst_row_width);
std::swap(l_data[1], r_data[1]); dst_offset += dst_row_size;
std::swap(l_data[2], r_data[2]); src_offset += src_row_size;
std::swap(l_line_size[0], r_line_size[0]);
std::swap(l_line_size[1], r_line_size[1]);
std::swap(l_line_size[2], r_line_size[2]);
} }
} }


Expand Down
13 changes: 9 additions & 4 deletions src/input.h
Expand Up @@ -65,6 +65,9 @@ class input
int _audio_channels; int _audio_channels;
enum decoder::audio_sample_format _audio_sample_format; enum decoder::audio_sample_format _audio_sample_format;
int64_t _duration; int64_t _duration;

uint8_t *_video_data[2][3];
size_t _video_data_line_size[2][3];
blob _audio_buffer; blob _audio_buffer;


public: public:
Expand Down Expand Up @@ -158,10 +161,12 @@ class input
/* Read the next video frame into an internal buffer. Return its time stamp in microseconds, /* Read the next video frame into an internal buffer. Return its time stamp in microseconds,
* or a negative value on end-of-file. */ * or a negative value on end-of-file. */
int64_t read_video_frame(); int64_t read_video_frame();
/* Get the video frame that is currently in the internal buffer, in the given format. */ /* Prepare the video frame that is currently in the internal buffer. Must be called before get_video_frame(). */
void get_video_frame(enum decoder::video_frame_format fmt, void prepare_video_frame();
uint8_t *l_data[3], size_t l_line_size[3], /* Get the video frame data from the internal buffer, for the given view (0=left, 1=right) and the given plane
uint8_t *r_data[3], size_t r_line_size[3]); * (depending on the video_frame_format()), and copy it to the given buffer with guaranteed 4-byte alignment for
* each row. */
void get_video_frame(int view, int plane, void *buf);
/* Release the video frame from the internal buffer */ /* Release the video frame from the internal buffer */
void release_video_frame(); void release_video_frame();


Expand Down
16 changes: 12 additions & 4 deletions src/player.cpp
Expand Up @@ -434,14 +434,22 @@ void player::run_step(bool *more_steps, int64_t *seek_to, bool *prep_frame, bool
} }
} }


void player::get_video_frame(enum decoder::video_frame_format fmt) void player::get_video_frame()
{ {
_input->get_video_frame(fmt, _l_data, _l_line_size, _r_data, _r_line_size); _input->prepare_video_frame();
} }


void player::prepare_video_frame(video_output *vo) void player::prepare_video_frame(video_output *vo)
{ {
vo->prepare(_l_data, _l_line_size, _r_data, _r_line_size); for (int i = 0; i < (_input->video_is_mono() ? 1 : 2); i++)
{
for (int j = 0; j < decoder::video_frame_format_planes(_input->video_frame_format()); j++)
{
void *buf = vo->prepare_start(i, j);
_input->get_video_frame(i, j, buf);
vo->prepare_finish(i, j);
}
}
} }


void player::release_video_frame() void player::release_video_frame()
Expand Down Expand Up @@ -518,7 +526,7 @@ void player::run()
} }
if (prep_frame) if (prep_frame)
{ {
get_video_frame(_input->video_frame_format()); get_video_frame();
prepare_video_frame(_video_output); prepare_video_frame(_video_output);
release_video_frame(); release_video_frame();
} }
Expand Down
4 changes: 1 addition & 3 deletions src/player.h
Expand Up @@ -77,8 +77,6 @@ class player
bool _pause_request; bool _pause_request;
int64_t _seek_request; int64_t _seek_request;


uint8_t *_l_data[3], *_r_data[3];
size_t _l_line_size[3], _r_line_size[3];
void *_audio_data; void *_audio_data;
size_t _required_audio_data_size; size_t _required_audio_data_size;
int64_t _pause_start; int64_t _pause_start;
Expand Down Expand Up @@ -114,7 +112,7 @@ class player
void make_master(); void make_master();
void run_step(bool *more_steps, int64_t *seek_to, bool *prep_frame, bool *drop_frame, bool *display_frame); void run_step(bool *more_steps, int64_t *seek_to, bool *prep_frame, bool *drop_frame, bool *display_frame);
void seek(int64_t seek_to); void seek(int64_t seek_to);
void get_video_frame(enum decoder::video_frame_format fmt); void get_video_frame();
void prepare_video_frame(video_output *vo); void prepare_video_frame(video_output *vo);
void release_video_frame(); void release_video_frame();
input *get_input() { return _input; } input *get_input() { return _input; }
Expand Down
2 changes: 1 addition & 1 deletion src/player_equalizer.cpp
Expand Up @@ -136,7 +136,7 @@ class player_eq_node : public player


void eq_get_frame() void eq_get_frame()
{ {
get_video_frame(get_input()->video_frame_format()); get_video_frame();
} }


void eq_release_frame() void eq_release_frame()
Expand Down
2 changes: 1 addition & 1 deletion src/player_qt.cpp
Expand Up @@ -102,7 +102,7 @@ bool player_qt_internal::playloop_step()
} }
if (prep_frame) if (prep_frame)
{ {
get_video_frame(get_input()->video_frame_format()); get_video_frame();
prepare_video_frame(get_video_output()); prepare_video_frame(get_video_output());
release_video_frame(); release_video_frame();
} }
Expand Down
12 changes: 8 additions & 4 deletions src/video_output.h
Expand Up @@ -100,10 +100,14 @@ class video_output : public controller
/* Get current state */ /* Get current state */
virtual const video_output_state &state() const = 0; virtual const video_output_state &state() const = 0;


/* Prepare a left/right view pair for display */ /* Prepare a left/right view pair for display.
virtual void prepare( * The video data is organized in planes, depending on the frame format.
uint8_t *l_data[3], size_t l_line_size[3], * First, call prepare_start() to get a buffer. Then copy the plane data
uint8_t *r_data[3], size_t r_line_size[3]) = 0; * to this buffer, with a 4-byte alignment of line lengths. Then, call
* prepare_finish() with the same parameters and this buffer. Repeat for
* all planes in both views. */
virtual void *prepare_start(int view, int plane) = 0;
virtual void prepare_finish(int view, int plane) = 0;
/* Display the prepared left/right view pair */ /* Display the prepared left/right view pair */
virtual void activate() = 0; virtual void activate() = 0;
/* Process window system events */ /* Process window system events */
Expand Down

0 comments on commit 795897c

Please sign in to comment.