X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=ycbcr_input.h;fp=ycbcr_input.h;h=fd9db273d52ba1a049c0ff98411f507a97ccc723;hb=9dcbd93164611ea111cc29519c18193d4f571ac1;hp=0000000000000000000000000000000000000000;hpb=ef82f39846c48a654b63797b78bf8b0b8935d348;p=movit diff --git a/ycbcr_input.h b/ycbcr_input.h new file mode 100644 index 0000000..fd9db27 --- /dev/null +++ b/ycbcr_input.h @@ -0,0 +1,95 @@ +#ifndef _YCBCR_INPUT_H +#define _YCBCR_INPUT_H 1 + +// YCbCrInput is for handling planar 8-bit Y'CbCr (also sometimes, usually rather +// imprecisely, called “YUV”), which is typically what you get from a video decoder. +// It upsamples planes as needed, using the default linear upsampling OpenGL gives you. + +#include "input.h" + +struct YCbCrFormat { + // Which formula for Y' to use. + YCbCrLumaCoefficients luma_coefficients; + + // If true, assume Y'CbCr coefficients are full-range, ie. go from 0 to 255 + // instead of the limited 220/225 steps in classic MPEG. For instance, + // JPEG uses the Rec. 601 luma coefficients, but full range. + bool full_range; + + // Sampling factors for chroma components. For no subsampling (4:4:4), + // set both to 1. + unsigned chroma_subsampling_x, chroma_subsampling_y; + + // Positioning of the chroma samples. MPEG-1 and JPEG is (0.5, 0.5); + // MPEG-2 and newer typically are (0.0, 0.5). + float chroma_x_position, chroma_y_position; +}; + +class YCbCrInput : public Input { +public: + YCbCrInput(const ImageFormat &image_format, + const YCbCrFormat &ycbcr_format, + unsigned width, unsigned height); + + // Create the texture itself. We cannot do this in the constructor, + // because we don't necessarily know all the settings (sRGB texture, + // mipmap generation) at that point. + void finalize(); + + virtual bool can_output_linear_gamma() const { return false; } + + std::string output_fragment_shader(); + + // Uploads the texture if it has changed since last time. + void set_gl_state(GLuint glsl_program_num, const std::string& prefix, unsigned *sampler_num); + + ColorSpace get_color_space() const { return image_format.color_space; } + GammaCurve get_gamma_curve() const { return image_format.gamma_curve; } + + // Tells the input where to fetch the actual pixel data. Note that if you change + // this data, you must either call set_pixel_data() again (using the same pointer + // is fine), or invalidate_pixel_data(). Otherwise, the texture won't be re-uploaded + // on subsequent frames. + void set_pixel_data(unsigned channel, const unsigned char *pixel_data) + { + assert(channel >= 0 && channel < 3); + this->pixel_data[channel] = pixel_data; + invalidate_pixel_data(); + } + + void invalidate_pixel_data() + { + needs_update = true; + } + + const unsigned char *get_pixel_data(unsigned channel) const + { + assert(channel >= 0 && channel < 3); + return pixel_data[channel]; + } + + void set_pitch(unsigned channel, unsigned pitch) { + assert(!finalized); + assert(channel >= 0 && channel < 3); + this->pitch[channel] = pitch; + } + + unsigned get_pitch(unsigned channel) { + assert(channel >= 0 && channel < 3); + return pitch[channel]; + } + +private: + ImageFormat image_format; + YCbCrFormat ycbcr_format; + GLuint pbos[3], texture_num[3]; + bool needs_update, finalized; + + int needs_mipmaps; + + unsigned width, height, widths[3], heights[3]; + const unsigned char *pixel_data[3]; + unsigned pitch[3]; +}; + +#endif // !defined(_YCBCR_INPUT_H)