@@ -364,14 +364,10 @@ static void create_avi_file(const uint16_t width, const uint16_t height,
364
364
// We always write non-double-scanned and non-pixel-doubled frames in raw
365
365
// video capture mode :
366
366
//
367
- // - Pixel-doubling is not a problem as that's always performed as a
368
- // post-processing step; it's never "baked-into" the rendered image.
369
- // We just need to completely ignore the `double_width` flag.
370
- //
371
- // - Double scanning can be either "baked-in" or performed in post-processing.
372
- // Ignoring the `double_height` flag takes care of the post-processing
373
- // variety, but for "baked-in" double scanning, we need to skip every second
374
- // row.
367
+ // Double scanning and pixel doubling can be either "baked-in" or performed in
368
+ // post-processing. Ignoring the `double_height` and `double_width` flags
369
+ // takes care of the post-processing variety, but for the "baked-in" variants
370
+ // we need to skip every second row or pixel.
375
371
//
376
372
// So, for example, the 320x200 13h VGA mode is always written as 320x200 in
377
373
// raw capture mode regardless of the state of the width & height doubling
@@ -388,15 +384,16 @@ static void compress_raw_frame(const RenderedImage& image)
388
384
const auto & src = image.params ;
389
385
auto src_row = image.image_data ;
390
386
391
- // We always write non-double-scanned frames in raw video capture mode.
392
- // Therefore, to reconstruct the raw image, we must skip every second
393
- // row if we're dealing with "baked in" double scanning.
387
+ // To reconstruct the raw image, we must skip every second row
388
+ // when dealing with "baked-in" double scanning.
389
+ const auto raw_height = (src.height / (src.rendered_double_scan ? 2 : 1 ));
390
+ const auto src_pitch = (image.pitch * (src.rendered_double_scan ? 2 : 1 ));
394
391
395
- const auto raw_height = (src.height /
396
- (image.params .rendered_double_scan ? 2 : 1 ));
392
+ // To reconstruct the raw image, we must skip every second pixel
393
+ // when dealing with "baked-in" pixel doubling.
394
+ const auto raw_width = (src.width / (src.rendered_pixel_doubling ? 2 : 1 ));
397
395
398
- const auto src_pitch = (image.pitch *
399
- (image.params .rendered_double_scan ? 2 : 1 ));
396
+ const auto pixel_skip_count = (src.rendered_pixel_doubling ? 1 : 0 );
400
397
401
398
auto compress_row = [&](const uint8_t * row_buffer) {
402
399
video.codec ->CompressLines (1 , &row_buffer);
@@ -409,7 +406,8 @@ static void compress_raw_frame(const RenderedImage& image)
409
406
// that this is a shortcut scenario; hard-code it to false to exercise
410
407
// the rote version below.
411
408
412
- const auto can_use_src_directly = (src_bpp == dest_bpp);
409
+ const auto can_use_src_directly = (src_bpp == dest_bpp &&
410
+ pixel_skip_count == 0 );
413
411
if (can_use_src_directly) {
414
412
for (auto i = 0 ; i < raw_height; ++i, src_row += src_pitch) {
415
413
compress_row (src_row);
@@ -427,10 +425,13 @@ static void compress_raw_frame(const RenderedImage& image)
427
425
dest_row.resize (dest_row_bytes, 0 );
428
426
}
429
427
428
+ const auto src_advance = src_bpp * (pixel_skip_count + 1 );
429
+
430
430
for (auto i = 0 ; i < raw_height; ++i, src_row += src_pitch) {
431
431
auto src_pixel = src_row;
432
432
auto dest_pixel = dest_row.data ();
433
- for (auto j = 0 ; j < src.width ; ++j, src_pixel += src_bpp) {
433
+
434
+ for (auto j = 0 ; j < raw_width; ++j, src_pixel += src_advance) {
434
435
std::memcpy (dest_pixel, src_pixel, src_bpp);
435
436
dest_pixel += dest_bpp;
436
437
}
@@ -443,30 +444,31 @@ void capture_video_add_frame(const RenderedImage& image, const float frames_per_
443
444
const auto & src = image.params ;
444
445
assert (src.width <= SCALER_MAXWIDTH);
445
446
446
- // Pixel-doubling is never "baked-in", so we always write the frames
447
- // non-pixel-doubled. The only exception is composite modes; these are
448
- // rendered at 2x width and we want to write them as such (we need enough
449
- // horizontal resolution to properly represent the composite artifacts).
450
- const auto video_width = src.width ;
447
+ // To reconstruct the raw image, we must skip every second row when
448
+ // dealing with "baked-in" double scanning.
449
+ const auto raw_width = check_cast<uint16_t >(
450
+ src.width / (src.rendered_pixel_doubling ? 2 : 1 ));
451
451
452
- // We always write non-double-scanned frames in raw video capture mode
453
- const auto video_height = src.video_mode .height ;
452
+ // To reconstruct the raw image, we must skip every second pixel
453
+ // when dealing with "baked-in" pixel doubling.
454
+ const auto raw_height = check_cast<uint16_t >(
455
+ src.height / (src.rendered_double_scan ? 2 : 1 ));
454
456
455
457
// Disable capturing if any of the test fails
456
- if (video.handle && (video.width != video_width || video.height != video_height ||
458
+ if (video.handle && (video.width != raw_width || video.height != raw_height ||
457
459
video.pixel_format != src.pixel_format ||
458
460
video.frames_per_second != frames_per_second)) {
459
461
capture_video_finalise ();
460
462
}
461
463
462
- const auto format = to_zmbv_format (src.pixel_format );
464
+ const auto zmbv_format = to_zmbv_format (src.pixel_format );
463
465
464
466
if (!video.handle ) {
465
- create_avi_file (video_width ,
466
- video_height ,
467
+ create_avi_file (raw_width ,
468
+ raw_height ,
467
469
src.pixel_format ,
468
470
frames_per_second,
469
- format );
471
+ zmbv_format );
470
472
}
471
473
if (!video.handle ) {
472
474
return ;
@@ -475,7 +477,7 @@ void capture_video_add_frame(const RenderedImage& image, const float frames_per_
475
477
const auto codec_flags = (video.frames % 300 == 0 ) ? 1 : 0 ;
476
478
477
479
if (!video.codec ->PrepareCompressFrame (codec_flags,
478
- format ,
480
+ zmbv_format ,
479
481
image.palette_data ,
480
482
video.buf .data (),
481
483
video.buf_size )) {
0 commit comments