Permalink
Browse files

Improve and fix the upload of video data to textures.

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 795897c6131f802afe8c1f793324e31d06161e59
Showing with 195 additions and 159 deletions.
  1. +13 −0 src/decoder.cpp
  2. +1 −0 src/decoder.h
  3. +73 −74 src/input.cpp
  4. +9 −4 src/input.h
  5. +12 −4 src/player.cpp
  6. +1 −3 src/player.h
  7. +1 −1 src/player_equalizer.cpp
  8. +1 −1 src/player_qt.cpp
  9. +8 −4 src/video_output.h
  10. +73 −65 src/video_output_opengl.cpp
  11. +3 −3 src/video_output_opengl.h
View
@@ -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)
{
switch (f)
View
@@ -42,6 +42,7 @@ class decoder
};
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 */
View
@@ -22,6 +22,7 @@
#include "config.h"
#include <cctype>
+#include <cstdlib>
#include "debug.h"
#include "exc.h"
@@ -472,101 +473,99 @@ int64_t input::read_video_frame()
return t;
}
-void input::get_video_frame(enum decoder::video_frame_format fmt,
- uint8_t *l_data[3], size_t l_line_size[3],
- uint8_t *r_data[3], size_t r_line_size[3])
+void input::prepare_video_frame()
{
- uint8_t *data[3], *data1[3];
- size_t line_size[3], line_size1[3];
+ _decoders.at(_video_decoders[0])->get_video_frame(_video_streams[0], video_frame_format(),
+ _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)
{
case separate:
- _decoders.at(_video_decoders[1])->get_video_frame(_video_streams[1], fmt, data1, line_size1);
- l_data[0] = data[0];
- l_data[1] = data[1];
- 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];
+ src = _video_data[view][plane];
+ src_row_size = _video_data_line_size[view][plane];
+ src_offset = 0;
break;
case top_bottom:
case top_bottom_half:
- l_data[0] = data[0];
- l_data[1] = data[1];
- 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] = 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];
+ src = _video_data[0][plane];
+ src_row_size = _video_data_line_size[0][plane];
+ src_offset = view * height * src_row_size;
break;
case left_right:
case left_right_half:
- l_data[0] = data[0];
- l_data[1] = data[1];
- 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] = 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];
+ src = _video_data[0][plane];
+ src_row_size = _video_data_line_size[0][plane];
+ src_offset = view * dst_row_width;
break;
case even_odd_rows:
- l_data[0] = data[0];
- l_data[1] = data[1];
- l_data[2] = data[2];
- 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];
+ src = _video_data[0][plane];
+ src_row_size = 2 * _video_data_line_size[0][plane];
+ src_offset = view * _video_data_line_size[0][plane];
break;
case mono:
- l_data[0] = data[0];
- l_data[1] = data[1];
- 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] = 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];
+ src = _video_data[0][plane];
+ src_row_size = _video_data_line_size[0][plane];
+ src_offset = 0;
break;
case automatic:
/* cannot happen */
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::swap(l_data[1], r_data[1]);
- std::swap(l_data[2], r_data[2]);
- 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]);
+ std::memcpy(dst + dst_offset, src + src_offset, dst_row_width);
+ dst_offset += dst_row_size;
+ src_offset += src_row_size;
}
}
View
@@ -65,6 +65,9 @@ class input
int _audio_channels;
enum decoder::audio_sample_format _audio_sample_format;
int64_t _duration;
+
+ uint8_t *_video_data[2][3];
+ size_t _video_data_line_size[2][3];
blob _audio_buffer;
public:
@@ -158,10 +161,12 @@ class input
/* Read the next video frame into an internal buffer. Return its time stamp in microseconds,
* or a negative value on end-of-file. */
int64_t read_video_frame();
- /* Get the video frame that is currently in the internal buffer, in the given format. */
- void get_video_frame(enum decoder::video_frame_format fmt,
- uint8_t *l_data[3], size_t l_line_size[3],
- uint8_t *r_data[3], size_t r_line_size[3]);
+ /* Prepare the video frame that is currently in the internal buffer. Must be called before get_video_frame(). */
+ void prepare_video_frame();
+ /* Get the video frame data from the internal buffer, for the given view (0=left, 1=right) and the given plane
+ * (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 */
void release_video_frame();
View
@@ -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)
{
- 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()
@@ -518,7 +526,7 @@ void player::run()
}
if (prep_frame)
{
- get_video_frame(_input->video_frame_format());
+ get_video_frame();
prepare_video_frame(_video_output);
release_video_frame();
}
View
@@ -77,8 +77,6 @@ class player
bool _pause_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;
size_t _required_audio_data_size;
int64_t _pause_start;
@@ -114,7 +112,7 @@ class player
void make_master();
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 get_video_frame(enum decoder::video_frame_format fmt);
+ void get_video_frame();
void prepare_video_frame(video_output *vo);
void release_video_frame();
input *get_input() { return _input; }
View
@@ -136,7 +136,7 @@ class player_eq_node : public player
void eq_get_frame()
{
- get_video_frame(get_input()->video_frame_format());
+ get_video_frame();
}
void eq_release_frame()
View
@@ -102,7 +102,7 @@ bool player_qt_internal::playloop_step()
}
if (prep_frame)
{
- get_video_frame(get_input()->video_frame_format());
+ get_video_frame();
prepare_video_frame(get_video_output());
release_video_frame();
}
View
@@ -100,10 +100,14 @@ class video_output : public controller
/* Get current state */
virtual const video_output_state &state() const = 0;
- /* Prepare a left/right view pair for display */
- virtual void prepare(
- uint8_t *l_data[3], size_t l_line_size[3],
- uint8_t *r_data[3], size_t r_line_size[3]) = 0;
+ /* Prepare a left/right view pair for display.
+ * The video data is organized in planes, depending on the frame format.
+ * First, call prepare_start() to get a buffer. Then copy the plane data
+ * 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 */
virtual void activate() = 0;
/* Process window system events */
Oops, something went wrong.

0 comments on commit 795897c

Please sign in to comment.