FrameSource.hh 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. #ifndef FRAMESOURCE_HH
  2. #define FRAMESOURCE_HH
  3. #include "PixelFormat.hh"
  4. #include "aligned.hh"
  5. #include <algorithm>
  6. #include <cassert>
  7. namespace openmsx {
  8. /** Interface for getting lines from a video frame.
  9. */
  10. class FrameSource
  11. {
  12. public:
  13. /** What role does this frame play in interlacing?
  14. */
  15. enum FieldType {
  16. /** Interlacing is off for this frame.
  17. */
  18. FIELD_NONINTERLACED,
  19. /** Interlacing is on and this is an even frame.
  20. */
  21. FIELD_EVEN,
  22. /** Interlacing is on and this is an odd frame.
  23. */
  24. FIELD_ODD
  25. };
  26. /** (Re)initialize an existing FrameSource. This method sets the
  27. * Fieldtype and flushes the 'getLinePtr' buffers.
  28. */
  29. void init(FieldType fieldType_) { fieldType = fieldType_; }
  30. /** Gets the role this frame plays in interlacing.
  31. */
  32. FieldType getField() const {
  33. return fieldType;
  34. }
  35. /** Gets the number of lines in this frame.
  36. */
  37. unsigned getHeight() const {
  38. return height;
  39. }
  40. /** Gets the number of display pixels on the given line.
  41. * @return line width (=1 for a vertical border line)
  42. */
  43. virtual unsigned getLineWidth(unsigned line) const = 0;
  44. /** Get the width of (all) lines in this frame.
  45. * This only makes sense when all lines have the same width, so this
  46. * methods asserts that all lines actually have the same width. This
  47. * is for example not always the case for MSX frames, but it is for
  48. * video frames (for superimpose).
  49. */
  50. unsigned getWidth() const {
  51. assert(height > 0);
  52. unsigned result = getLineWidth(0);
  53. for (unsigned line = 1; line < height; ++line) {
  54. assert(result == getLineWidth(line));
  55. }
  56. return result;
  57. }
  58. /** Get the (single) color of the given line.
  59. * Typically this will be used to get the color of a vertical border
  60. * line. But it's fine to call this on non-border lines as well, in
  61. * that case the color of the first pixel of the line is returned.
  62. */
  63. template <typename Pixel>
  64. inline Pixel getLineColor(unsigned line) const {
  65. alignas(SSE_ALIGNMENT) Pixel buf[1280]; // large enough for widest line
  66. unsigned width; // not used
  67. return reinterpret_cast<const Pixel*>(
  68. getLineInfo(line, width, buf, 1280))[0];
  69. }
  70. /** Gets a pointer to the pixels of the given line number.
  71. * The line returned is guaranteed to have the given width. If the
  72. * original line had a different width the result will be computed in
  73. * the provided work buffer. So that buffer should be big enough to
  74. * hold the scaled line. This also means the lifetime of the result
  75. * is tied to the lifetime of that work buffer. In any case the return
  76. * value of this function will point to the line data (some internal
  77. * buffer or the work buffer).
  78. */
  79. template <typename Pixel>
  80. inline const Pixel* getLinePtr(int line, unsigned width, Pixel* buf) const
  81. {
  82. line = std::min<unsigned>(std::max(0, line), getHeight() - 1);
  83. unsigned internalWidth;
  84. auto* internalData = reinterpret_cast<const Pixel*>(
  85. getLineInfo(line, internalWidth, buf, width));
  86. if (internalWidth == width) {
  87. return internalData;
  88. } else {
  89. // slow path, non-inlined
  90. // internalData might be equal to buf
  91. scaleLine(internalData, buf, internalWidth, width);
  92. return buf;
  93. }
  94. }
  95. /** Similar to the above getLinePtr() method, but now tries to get
  96. * multiple lines at once. This is not always possible, so the actual
  97. * number of lines is returned in 'actualLines', it will always be at
  98. * least 1.
  99. */
  100. template <typename Pixel>
  101. inline const Pixel* getMultiLinePtr(
  102. int line, unsigned numLines, unsigned& actualLines,
  103. unsigned width, Pixel* buf) const
  104. {
  105. actualLines = 1;
  106. if ((line < 0) || (int(height) <= line)) {
  107. return getLinePtr(line, width, buf);
  108. }
  109. unsigned internalWidth;
  110. auto* internalData = reinterpret_cast<const Pixel*>(
  111. getLineInfo(line, internalWidth, buf, width));
  112. if (internalWidth != width) {
  113. scaleLine(internalData, buf, internalWidth, width);
  114. return buf;
  115. }
  116. if (!hasContiguousStorage()) {
  117. return internalData;
  118. }
  119. while (--numLines) {
  120. ++line;
  121. if ((line == int(height)) || (getLineWidth(line) != width)) {
  122. break;
  123. }
  124. ++actualLines;
  125. }
  126. return internalData;
  127. }
  128. /** Abstract implementation of getLinePtr().
  129. * Pixel type is unspecified (implementations that care about the
  130. * exact type should get it via some other mechanism).
  131. * @param line The line number for the requisted line.
  132. * @param lineWidth Output parameter, the width of the returned line
  133. * in pixel units.
  134. * @param buf Buffer space that can _optionally_ be used by the
  135. * implementation.
  136. * @param bufWidth The size of the above buffer, in pixel units.
  137. * @return Pointer to the first pixel of the requested line. This might
  138. * be the same as the given 'buf' parameter or it might be some
  139. * internal buffer.
  140. */
  141. virtual const void* getLineInfo(
  142. unsigned line, unsigned& lineWidth,
  143. void* buf, unsigned bufWidth) const = 0;
  144. /** Get a pointer to a given line in this frame, the frame is scaled
  145. * to 320x240 pixels. The difference between this method and
  146. * getLinePtr() is that this method also does vertical scaling.
  147. * This is used for video recording.
  148. */
  149. template <typename Pixel>
  150. const Pixel* getLinePtr320_240(unsigned line, Pixel* buf) const;
  151. /** Get a pointer to a given line in this frame, the frame is scaled
  152. * to 640x480 pixels. Same as getLinePtr320_240, but then for a
  153. * higher resolution output.
  154. */
  155. template <typename Pixel>
  156. const Pixel* getLinePtr640_480(unsigned line, Pixel* buf) const;
  157. /** Get a pointer to a given line in this frame, the frame is scaled
  158. * to 960x720 pixels. Same as getLinePtr320_240, but then for a
  159. * higher resolution output.
  160. */
  161. template <typename Pixel>
  162. const Pixel* getLinePtr960_720(unsigned line, Pixel* buf) const;
  163. /** Returns the distance (in pixels) between two consecutive lines.
  164. * Is meant to be used in combination with getMultiLinePtr(). The
  165. * result is only meaningful when hasContiguousStorage() returns
  166. * true (also only in that case does getMultiLinePtr() return more
  167. * than 1 line).
  168. */
  169. virtual unsigned getRowLength() const {
  170. return 0;
  171. }
  172. const PixelFormat& getPixelFormat() const {
  173. return pixelFormat;
  174. }
  175. protected:
  176. explicit FrameSource(const PixelFormat& format);
  177. ~FrameSource() = default;
  178. void setHeight(unsigned height_) { height = height_; }
  179. /** Returns true when two consecutive rows are also consecutive in
  180. * memory.
  181. */
  182. virtual bool hasContiguousStorage() const {
  183. return false;
  184. }
  185. template <typename Pixel> void scaleLine(
  186. const Pixel* in, Pixel* out,
  187. unsigned inWidth, unsigned outWidth) const;
  188. private:
  189. /** Pixel format. Needed for getLinePtr scaling
  190. */
  191. const PixelFormat& pixelFormat;
  192. /** Number of lines in this frame.
  193. */
  194. unsigned height;
  195. FieldType fieldType;
  196. };
  197. } // namespace openmsx
  198. #endif // FRAMESOURCE_HH