DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/hardware/hardware.cpp
00001 /*
00002  *  Copyright (C) 2002-2020  The DOSBox Team
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License along
00015  *  with this program; if not, write to the Free Software Foundation, Inc.,
00016  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  */
00018 
00019 
00020 #include <string.h>
00021 #include <stdlib.h>
00022 #include <stdio.h>
00023 #include "dosbox.h"
00024 #include "control.h"
00025 #include "hardware.h"
00026 #include "setup.h"
00027 #include "support.h"
00028 #include "mem.h"
00029 #include "mapper.h"
00030 #include "pic.h"
00031 #include "mixer.h"
00032 #include "render.h"
00033 #include "cross.h"
00034 
00035 #if (C_SSHOT)
00036 #include <zlib.h>
00037 #include <png.h>
00038 #include "../libs/zmbv/zmbv.h"
00039 #endif
00040 
00041 #include "riff_wav_writer.h"
00042 #include "avi_writer.h"
00043 #include "rawint.h"
00044 
00045 #include <map>
00046 
00047 #if (C_AVCODEC)
00048 extern "C" {
00049 #include <libavutil/pixfmt.h>
00050 #include <libswscale/swscale.h>
00051 #include <libavcodec/avcodec.h>
00052 #include <libavformat/avformat.h>
00053 #include <libavformat/avio.h>
00054 }
00055 
00056 /* This code now requires FFMPEG 4.0.2 or higher */
00057 # if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58,18,100)
00058 #  error Your libavcodec is too old. Update FFMPEG.
00059 # endif
00060 
00061 #endif
00062 
00063 bool            skip_encoding_unchanged_frames = false;
00064 
00065 #if (C_AVCODEC)
00066 bool ffmpeg_init = false;
00067 AVFormatContext*        ffmpeg_fmt_ctx = NULL;
00068 AVCodec*                ffmpeg_vid_codec = NULL;
00069 AVCodecContext*         ffmpeg_vid_ctx = NULL;
00070 AVCodec*                ffmpeg_aud_codec = NULL;
00071 AVCodecContext*         ffmpeg_aud_ctx = NULL;
00072 AVStream*               ffmpeg_vid_stream = NULL;
00073 AVStream*               ffmpeg_aud_stream = NULL;
00074 AVFrame*                ffmpeg_aud_frame = NULL;
00075 AVFrame*                ffmpeg_vid_frame = NULL;
00076 AVFrame*                ffmpeg_vidrgb_frame = NULL;
00077 SwsContext*             ffmpeg_sws_ctx = NULL;
00078 bool                    ffmpeg_avformat_began = false;
00079 unsigned int            ffmpeg_aud_write = 0;
00080 Bit64u                  ffmpeg_audio_sample_counter = 0;
00081 Bit64u                  ffmpeg_video_frame_time_offset = 0;
00082 Bit64u                  ffmpeg_video_frame_last_time = 0;
00083 
00084 int             ffmpeg_yuv_format_choice = -1;  // -1 default  4 = 444   2 = 422   0 = 420
00085 
00086 AVPixelFormat ffmpeg_choose_pixfmt(const int x) {
00087     (void)x;//UNUSED
00088     if (ffmpeg_yuv_format_choice == 4)
00089         return AV_PIX_FMT_YUV444P;
00090     else if (ffmpeg_yuv_format_choice == 2)
00091         return AV_PIX_FMT_YUV422P;
00092     else if (ffmpeg_yuv_format_choice == 0)
00093         return AV_PIX_FMT_YUV420P;
00094 
00095     // default
00096     // TODO: but this default should also be affected by what the codec supports!
00097     return AV_PIX_FMT_YUV444P;
00098 }
00099 
00100 void ffmpeg_closeall() {
00101         if (ffmpeg_fmt_ctx != NULL) {
00102                 if (ffmpeg_avformat_began) {
00103                         av_write_trailer(ffmpeg_fmt_ctx);
00104                         ffmpeg_avformat_began = false;
00105                 }
00106                 avio_close(ffmpeg_fmt_ctx->pb);
00107                 avformat_free_context(ffmpeg_fmt_ctx);
00108                 ffmpeg_fmt_ctx = NULL;
00109         }
00110         if (ffmpeg_vid_ctx != NULL) {
00111                 avcodec_close(ffmpeg_vid_ctx);
00112                 ffmpeg_vid_ctx = NULL;
00113         }
00114         if (ffmpeg_aud_ctx != NULL) {
00115                 avcodec_close(ffmpeg_aud_ctx);
00116                 ffmpeg_aud_ctx = NULL;
00117         }
00118         if (ffmpeg_vidrgb_frame != NULL) {
00119                 av_frame_free(&ffmpeg_vidrgb_frame);
00120                 ffmpeg_vidrgb_frame = NULL;
00121         }
00122         if (ffmpeg_vid_frame != NULL) {
00123                 av_frame_free(&ffmpeg_vid_frame);
00124                 ffmpeg_vid_frame = NULL;
00125         }
00126         if (ffmpeg_aud_frame != NULL) {
00127                 av_frame_free(&ffmpeg_aud_frame);
00128                 ffmpeg_aud_frame = NULL;
00129         }
00130         if (ffmpeg_sws_ctx != NULL) {
00131                 sws_freeContext(ffmpeg_sws_ctx);
00132                 ffmpeg_sws_ctx = NULL;
00133         }
00134         ffmpeg_video_frame_time_offset = 0;
00135         ffmpeg_video_frame_last_time = 0;
00136         ffmpeg_aud_codec = NULL;
00137         ffmpeg_vid_codec = NULL;
00138         ffmpeg_vid_stream = NULL;
00139         ffmpeg_aud_stream = NULL;
00140         ffmpeg_aud_write = 0;
00141 }
00142 
00143 void ffmpeg_audio_frame_send() {
00144         AVPacket pkt;
00145         int gotit;
00146 
00147         av_init_packet(&pkt);
00148         if (av_new_packet(&pkt,65536) == 0) {
00149                 pkt.flags |= AV_PKT_FLAG_KEY;
00150 
00151                 if (avcodec_encode_audio2(ffmpeg_aud_ctx,&pkt,ffmpeg_aud_frame,&gotit) == 0) {
00152                         if (gotit) {
00153                                 pkt.pts = (int64_t)ffmpeg_audio_sample_counter;
00154                                 pkt.dts = (int64_t)ffmpeg_audio_sample_counter;
00155                                 pkt.stream_index = ffmpeg_aud_stream->index;
00156                                 av_packet_rescale_ts(&pkt,ffmpeg_aud_ctx->time_base,ffmpeg_aud_stream->time_base);
00157 
00158                                 if (av_interleaved_write_frame(ffmpeg_fmt_ctx,&pkt) < 0)
00159                                         LOG_MSG("WARNING: av_interleaved_write_frame failed");
00160                         }
00161                         else {
00162                                 LOG_MSG("DEBUG: avcodec_encode_audio2() delayed output");
00163                         }
00164                 }
00165                 else {
00166                         LOG_MSG("WARNING: avcodec_encode_audio2() failed to encode");
00167                 }
00168         }
00169         av_packet_unref(&pkt);
00170 
00171         ffmpeg_audio_sample_counter += (Bit64u)ffmpeg_aud_frame->nb_samples;
00172 }
00173 
00174 void ffmpeg_take_audio(Bit16s *raw,unsigned int samples) {
00175         if (ffmpeg_aud_codec == NULL || ffmpeg_aud_frame == NULL || ffmpeg_fmt_ctx == NULL) return;
00176 
00177         if ((unsigned long)ffmpeg_aud_write >= (unsigned long)ffmpeg_aud_frame->nb_samples) {
00178                 ffmpeg_audio_frame_send();
00179                 ffmpeg_aud_write = 0;
00180         }
00181 
00182         if (ffmpeg_aud_frame->format == AV_SAMPLE_FMT_FLTP) {
00183                 while (samples > 0) {
00184                         unsigned int op = (unsigned int)ffmpeg_aud_frame->nb_samples - ffmpeg_aud_write;
00185 
00186                         if (op > samples) op = samples;
00187 
00188                         while (op > 0) {
00189                                 /* fixed stereo 16-bit -> two channel planar float */
00190                                 ((float*)ffmpeg_aud_frame->data[0])[ffmpeg_aud_write] = (float)raw[0] / 32768;
00191                                 ((float*)ffmpeg_aud_frame->data[1])[ffmpeg_aud_write] = (float)raw[1] / 32768;
00192                                 ffmpeg_aud_write++;
00193                                 samples--;
00194                                 raw += 2;
00195                                 op--;
00196                         }
00197 
00198                         if ((unsigned long)ffmpeg_aud_write >= (unsigned long)ffmpeg_aud_frame->nb_samples) {
00199                                 ffmpeg_audio_frame_send();
00200                                 ffmpeg_aud_write = 0;
00201                         }
00202                 }
00203         }
00204         else if (ffmpeg_aud_frame->format == AV_SAMPLE_FMT_S16) {
00205                 while (samples > 0) {
00206                         unsigned int op = (unsigned int)ffmpeg_aud_frame->nb_samples - ffmpeg_aud_write;
00207 
00208                         if (op > samples) op = samples;
00209 
00210                         while (op > 0) {
00211                                 /* 16-bit stereo -> 16-bit stereo conversion */
00212                                 ((int16_t*)ffmpeg_aud_frame->data[0])[(ffmpeg_aud_write*2)+0] = raw[0];
00213                                 ((int16_t*)ffmpeg_aud_frame->data[0])[(ffmpeg_aud_write*2)+1] = raw[1];
00214                                 ffmpeg_aud_write++;
00215                                 samples--;
00216                                 raw += 2;
00217                                 op--;
00218                         }
00219 
00220                         if ((unsigned long)ffmpeg_aud_write >= (unsigned long)ffmpeg_aud_frame->nb_samples) {
00221                                 ffmpeg_audio_frame_send();
00222                                 ffmpeg_aud_write = 0;
00223                         }
00224                 }
00225         }
00226         else {
00227                 LOG_MSG("WARNING: Audio encoder expects unknown format %u",ffmpeg_aud_frame->format);
00228         }
00229 }
00230 
00231 void ffmpeg_reopen_video(double fps);
00232 
00233 void ffmpeg_flush_video() {
00234         if (ffmpeg_fmt_ctx != NULL) {
00235                 if (ffmpeg_vid_frame != NULL) {
00236                         bool again;
00237                         AVPacket pkt;
00238 
00239                         do {
00240                                 again=false;
00241                                 av_init_packet(&pkt);
00242                                 if (av_new_packet(&pkt,50000000/8) == 0) {
00243                                         int gotit=0;
00244                                         if (avcodec_encode_video2(ffmpeg_vid_ctx,&pkt,NULL,&gotit) == 0) {
00245                                                 if (gotit) {
00246                                                         Bit64u tm;
00247 
00248                                                         again = true;
00249                                                         tm = (uint64_t)pkt.pts;
00250                                                         pkt.stream_index = ffmpeg_vid_stream->index;
00251                                                         av_packet_rescale_ts(&pkt,ffmpeg_vid_ctx->time_base,ffmpeg_vid_stream->time_base);
00252                                                         pkt.pts += (int64_t)ffmpeg_video_frame_time_offset;
00253                                                         pkt.dts += (int64_t)ffmpeg_video_frame_time_offset;
00254 
00255                                                         if (av_interleaved_write_frame(ffmpeg_fmt_ctx,&pkt) < 0)
00256                                                                 LOG_MSG("WARNING: av_interleaved_write_frame failed");
00257 
00258                                                         pkt.pts = (int64_t)tm + (int64_t)1;
00259                                                         pkt.dts = (int64_t)tm + (int64_t)1;
00260                                                         av_packet_rescale_ts(&pkt,ffmpeg_vid_ctx->time_base,ffmpeg_vid_stream->time_base);
00261                                                         ffmpeg_video_frame_last_time = (uint64_t)pkt.pts;
00262                                                 }
00263                                         }
00264                                 }
00265                                 av_packet_unref(&pkt);
00266                         } while (again);
00267                 }
00268         }
00269 }
00270 
00271 void ffmpeg_flushout() {
00272         /* audio */
00273         if (ffmpeg_fmt_ctx != NULL) {
00274                 if (ffmpeg_aud_frame != NULL) {
00275                         bool again;
00276                         AVPacket pkt;
00277 
00278                         if (ffmpeg_aud_write != 0)
00279                                 ffmpeg_aud_frame->nb_samples = (int)ffmpeg_aud_write;
00280 
00281                         ffmpeg_audio_frame_send();
00282                         ffmpeg_aud_write = 0;
00283                         ffmpeg_aud_frame->nb_samples = 0;
00284 
00285                         do {
00286                                 again=false;
00287                                 av_init_packet(&pkt);
00288                                 if (av_new_packet(&pkt,65536) == 0) {
00289                                         int gotit=0;
00290                                         if (avcodec_encode_audio2(ffmpeg_aud_ctx,&pkt,NULL,&gotit) == 0) {
00291                                                 if (gotit) {
00292                                                         again = true;
00293                                                         pkt.stream_index = ffmpeg_aud_stream->index;
00294                                                         av_packet_rescale_ts(&pkt,ffmpeg_aud_ctx->time_base,ffmpeg_aud_stream->time_base);
00295 
00296                                                         if (av_interleaved_write_frame(ffmpeg_fmt_ctx,&pkt) < 0)
00297                                                                 LOG_MSG("WARNING: av_interleaved_write_frame failed");
00298                                                 }
00299                                         }
00300                                 }
00301                                 av_packet_unref(&pkt);
00302                         } while (again);
00303                 }
00304         }
00305 
00306         ffmpeg_flush_video();
00307 }
00308 #endif
00309 
00310 /* FIXME: This needs to be an enum */
00311 bool native_zmbv = false;
00312 bool export_ffmpeg = false;
00313 
00314 std::string capturedir;
00315 extern const char* RunningProgram;
00316 Bitu CaptureState = 0;
00317 
00318 #define WAVE_BUF 16*1024
00319 #define MIDI_BUF 4*1024
00320 
00321 static struct {
00322         struct {
00323                 riff_wav_writer *writer;
00324                 Bit16s buf[WAVE_BUF][2];
00325                 Bitu used;
00326                 Bit32u length;
00327                 Bit32u freq;
00328     } wave = {};
00329     struct {
00330         avi_writer  *writer;
00331                 Bitu            audiorate;
00332         std::map<std::string,size_t> name_to_stream_index;
00333     } multitrack_wave = {};
00334         struct {
00335                 FILE * handle;
00336                 Bit8u buffer[MIDI_BUF];
00337                 Bitu used,done;
00338                 Bit32u last;
00339     } midi = {};
00340         struct {
00341                 Bitu rowlen;
00342     } image = {};
00343 #if (C_SSHOT) || (C_AVCODEC)
00344         struct {
00345                 avi_writer      *writer;
00346                 Bitu            frames;
00347                 Bit16s          audiobuf[WAVE_BUF][2];
00348                 Bitu            audioused;
00349                 Bitu            audiorate;
00350                 Bitu            audiowritten;
00351                 VideoCodec      *codec;
00352                 Bitu            width, height, bpp;
00353                 Bitu            written;
00354                 float           fps;
00355                 int             bufSize;
00356                 void            *buf;
00357     } video = {};
00358 #endif
00359 } capture;
00360 
00361 #if (C_AVCODEC)
00362 unsigned int GFX_GetBShift();
00363 
00364 int ffmpeg_bpp_pick_rgb_format(int bpp) {
00365         // NTS: This requires some explanation. FFMPEG's pixfmt.h documents RGB555 as (msb)5R 5G 5B(lsb).
00366         //      So when we typecast two bytes in video ram as uint16_t we get XRRRRRGGGGGBBBBB.
00367         //
00368         //      But, RGB24 means that, byte by byte, we get R G B R G B ... which when typecast as uint32_t
00369         //      on little endian hosts becomes 0xXXBBGGRR.
00370         //
00371         //      RGBA would mean byte order R G B A R G B A ... which when typecast as uint32_t little endian
00372         //      becomes AABBGGRR.
00373         //
00374         //      Most of the platforms DOSBox-X runs on tend to arrange 24-bit bpp as uint32_t(0xRRGGBB) little
00375         //      endian, and 32-bit bpp as uint32_t(0xAARRGGBB).
00376         //
00377         //      So if the above text makes any sense, the RGB/BGR switch-up between 15/16bpp and 24/32bpp is
00378         //      NOT a coding error or a typo.
00379 
00380         // FIXME: Given the above explanation, this code needs to factor RGBA byte order vs host byte order
00381         //        to correctly specify the color format on any platform.
00382         if (bpp == 8)
00383                 return (GFX_GetBShift() == 0) ? AV_PIX_FMT_BGRA : AV_PIX_FMT_RGBA; // I can't get FFMPEG to do PAL8 -> YUV444P, so we'll just convert to RGBA on the fly
00384         else if (bpp == 15)
00385                 return (GFX_GetBShift() == 0) ? AV_PIX_FMT_RGB555 : AV_PIX_FMT_BGR555; // <- not a typo! not a mistake!
00386         else if (bpp == 16)
00387                 return (GFX_GetBShift() == 0) ? AV_PIX_FMT_RGB565 : AV_PIX_FMT_BGR565; // <- not a typo! not a mistake!
00388         else if (bpp == 24)
00389                 return (GFX_GetBShift() == 0) ? AV_PIX_FMT_BGR24 : AV_PIX_FMT_RGB24;
00390         else if (bpp == 32)
00391                 return (GFX_GetBShift() == 0) ? AV_PIX_FMT_BGRA : AV_PIX_FMT_RGBA;
00392 
00393         abort();//whut?
00394         return 0;
00395 }
00396 
00397 void ffmpeg_reopen_video(double fps,const int bpp) {
00398         if (ffmpeg_vid_ctx != NULL) {
00399                 avcodec_close(ffmpeg_vid_ctx);
00400                 ffmpeg_vid_ctx = NULL;
00401         }
00402         if (ffmpeg_vidrgb_frame != NULL) {
00403                 av_frame_free(&ffmpeg_vidrgb_frame);
00404                 ffmpeg_vidrgb_frame = NULL;
00405         }
00406         if (ffmpeg_vid_frame != NULL) {
00407                 av_frame_free(&ffmpeg_vid_frame);
00408                 ffmpeg_vid_frame = NULL;
00409         }
00410         if (ffmpeg_sws_ctx != NULL) {
00411                 sws_freeContext(ffmpeg_sws_ctx);
00412                 ffmpeg_sws_ctx = NULL;
00413         }
00414 
00415         LOG_MSG("Restarting video codec");
00416 
00417         // FIXME: This is copypasta! Consolidate!
00418         ffmpeg_vid_ctx = ffmpeg_vid_stream->codec = avcodec_alloc_context3(ffmpeg_vid_codec);
00419         if (ffmpeg_vid_ctx == NULL) E_Exit("Error: Unable to reopen vid codec");
00420         avcodec_get_context_defaults3(ffmpeg_vid_ctx,ffmpeg_vid_codec);
00421         ffmpeg_vid_ctx->bit_rate = 25000000; // TODO: make configuration option!
00422         ffmpeg_vid_ctx->keyint_min = 15; // TODO: make configuration option!
00423         ffmpeg_vid_ctx->time_base.num = 1000000;
00424         ffmpeg_vid_ctx->time_base.den = (int)(1000000 * fps);
00425         ffmpeg_vid_ctx->width = (int)capture.video.width;
00426         ffmpeg_vid_ctx->height = (int)capture.video.height;
00427         ffmpeg_vid_ctx->gop_size = 15; // TODO: make config option
00428         ffmpeg_vid_ctx->max_b_frames = 0;
00429         ffmpeg_vid_ctx->pix_fmt = ffmpeg_choose_pixfmt(ffmpeg_yuv_format_choice);
00430         ffmpeg_vid_ctx->thread_count = 0;               // auto-choose
00431         ffmpeg_vid_ctx->flags2 = AV_CODEC_FLAG2_FAST;
00432         ffmpeg_vid_ctx->qmin = 1;
00433         ffmpeg_vid_ctx->qmax = 63;
00434         ffmpeg_vid_ctx->rc_max_rate = ffmpeg_vid_ctx->bit_rate;
00435         ffmpeg_vid_ctx->rc_min_rate = ffmpeg_vid_ctx->bit_rate;
00436         ffmpeg_vid_ctx->rc_buffer_size = (4*1024*1024);
00437 
00438         /* 4:3 aspect ratio. FFMPEG thinks in terms of Pixel Aspect Ratio not Display Aspect Ratio */
00439         ffmpeg_vid_ctx->sample_aspect_ratio.num = 4 * (int)capture.video.height;
00440         ffmpeg_vid_ctx->sample_aspect_ratio.den = 3 * (int)capture.video.width;
00441 
00442         {
00443                 AVDictionary *opts = NULL;
00444 
00445                 av_dict_set(&opts,"preset","superfast",1);
00446                 av_dict_set(&opts,"aud","1",1);
00447 
00448                 if (avcodec_open2(ffmpeg_vid_ctx,ffmpeg_vid_codec,&opts) < 0) {
00449                         E_Exit("Unable to open H.264 codec");
00450                 }
00451 
00452                 av_dict_free(&opts);
00453         }
00454 
00455         ffmpeg_vid_frame = av_frame_alloc();
00456         ffmpeg_vidrgb_frame = av_frame_alloc();
00457         if (ffmpeg_aud_frame == NULL || ffmpeg_vid_frame == NULL || ffmpeg_vidrgb_frame == NULL)
00458                 E_Exit(" ");
00459 
00460         av_frame_set_colorspace(ffmpeg_vidrgb_frame,AVCOL_SPC_RGB);
00461         ffmpeg_vidrgb_frame->width = (int)capture.video.width;
00462         ffmpeg_vidrgb_frame->height = (int)capture.video.height;
00463         ffmpeg_vidrgb_frame->format = ffmpeg_bpp_pick_rgb_format(bpp);
00464         if (av_frame_get_buffer(ffmpeg_vidrgb_frame,64) < 0) {
00465                 E_Exit(" ");
00466         }
00467 
00468         av_frame_set_colorspace(ffmpeg_vid_frame,AVCOL_SPC_SMPTE170M);
00469         av_frame_set_color_range(ffmpeg_vidrgb_frame,AVCOL_RANGE_MPEG);
00470         ffmpeg_vid_frame->width = (int)capture.video.width;
00471         ffmpeg_vid_frame->height = (int)capture.video.height;
00472         ffmpeg_vid_frame->format = ffmpeg_vid_ctx->pix_fmt;
00473         if (av_frame_get_buffer(ffmpeg_vid_frame,64) < 0)
00474                 E_Exit(" ");
00475 
00476         ffmpeg_sws_ctx = sws_getContext(
00477                         // source
00478                         ffmpeg_vidrgb_frame->width,
00479                         ffmpeg_vidrgb_frame->height,
00480                         (AVPixelFormat)ffmpeg_vidrgb_frame->format,
00481                         // dest
00482                         ffmpeg_vid_frame->width,
00483                         ffmpeg_vid_frame->height,
00484                         (AVPixelFormat)ffmpeg_vid_frame->format,
00485                         // and the rest
00486                         ((ffmpeg_vid_frame->width == ffmpeg_vidrgb_frame->width && ffmpeg_vid_frame->height == ffmpeg_vidrgb_frame->height) ? SWS_POINT : SWS_BILINEAR),
00487                         NULL,NULL,NULL);
00488         if (ffmpeg_sws_ctx == NULL)
00489                 E_Exit(" ");
00490 }
00491 #endif
00492 
00493 std::string GetCaptureFilePath(const char * type,const char * ext) {
00494         if(capturedir.empty()) {
00495                 LOG_MSG("Please specify a capture directory");
00496                 return "";
00497         }
00498 
00499         Bitu last=0;
00500         char file_start[16];
00501         dir_information * dir;
00502         /* Find a filename to open */
00503         dir = open_directory(capturedir.c_str());
00504         if (!dir) {
00505                 //Try creating it first
00506                 Cross::CreateDir(capturedir);
00507                 dir=open_directory(capturedir.c_str());
00508                 if(!dir) {
00509                         LOG_MSG("Can't open dir %s for capturing %s",capturedir.c_str(),type);
00510                         return 0;
00511                 }
00512         }
00513         strcpy(file_start,RunningProgram);
00514         lowcase(file_start);
00515         strcat(file_start,"_");
00516         bool is_directory;
00517     char tempname[CROSS_LEN], sname[15];
00518     bool testRead = read_directory_first(dir, tempname, sname, is_directory );
00519     for ( ; testRead; testRead = read_directory_next(dir, tempname, sname, is_directory) ) {
00520                 char * test=strstr(tempname,ext);
00521                 if (!test || strlen(test)!=strlen(ext)) 
00522                         continue;
00523                 *test=0;
00524                 if (strncasecmp(tempname,file_start,strlen(file_start))!=0) continue;
00525                 Bitu num=(Bitu)atoi(&tempname[strlen(file_start)]);
00526                 if (num>=last) last=num+1;
00527         }
00528         close_directory( dir );
00529         char file_name[CROSS_LEN];
00530         sprintf(file_name,"%s%c%s%03d%s",capturedir.c_str(),CROSS_FILESPLIT,file_start,(int)last,ext);
00531         return file_name;
00532 }
00533 
00534 FILE * OpenCaptureFile(const char * type,const char * ext) {
00535         if(capturedir.empty()) {
00536                 LOG_MSG("Please specify a capture directory");
00537                 return 0;
00538         }
00539 
00540         Bitu last=0;
00541         char file_start[16];
00542         dir_information * dir;
00543         /* Find a filename to open */
00544         dir = open_directory(capturedir.c_str());
00545         if (!dir) {
00546                 //Try creating it first
00547                 Cross::CreateDir(capturedir);
00548                 dir=open_directory(capturedir.c_str());
00549                 if(!dir) {
00550                         LOG_MSG("Can't open dir %s for capturing %s",capturedir.c_str(),type);
00551                         return 0;
00552                 }
00553         }
00554         strcpy(file_start,RunningProgram);
00555         lowcase(file_start);
00556         strcat(file_start,"_");
00557         bool is_directory;
00558     char tempname[CROSS_LEN], sname[15];
00559     bool testRead = read_directory_first(dir, tempname, sname, is_directory );
00560     for ( ; testRead; testRead = read_directory_next(dir, tempname, sname, is_directory) ) {
00561                 char * test=strstr(tempname,ext);
00562                 if (!test || strlen(test)!=strlen(ext)) 
00563                         continue;
00564                 *test=0;
00565                 if (strncasecmp(tempname,file_start,strlen(file_start))!=0) continue;
00566                 Bitu num=(Bitu)atoi(&tempname[strlen(file_start)]);
00567                 if (num>=last) last=num+1;
00568         }
00569         close_directory( dir );
00570         char file_name[CROSS_LEN];
00571         sprintf(file_name,"%s%c%s%03d%s",capturedir.c_str(),CROSS_FILESPLIT,file_start,(int)last,ext);
00572         /* Open the actual file */
00573         FILE * handle=fopen(file_name,"wb");
00574         if (handle) {
00575                 LOG_MSG("Capturing %s to %s",type,file_name);
00576         } else {
00577                 LOG_MSG("Failed to open %s for capturing %s",file_name,type);
00578         }
00579         return handle;
00580 }
00581 
00582 #if (C_SSHOT)
00583 static void CAPTURE_AddAviChunk(const char * tag, Bit32u size, void * data, Bit32u flags, unsigned int streamindex) {
00584     (void)tag;//UNUSED
00585         if (capture.video.writer != NULL) {
00586                 if ((int)streamindex < capture.video.writer->avi_stream_alloc) {
00587                         avi_writer_stream *os = capture.video.writer->avi_stream + streamindex;
00588                         avi_writer_stream_write(capture.video.writer,os,data,size,flags);
00589                 }
00590         }
00591 }
00592 #endif
00593 
00594 #if (C_SSHOT)
00595 void CAPTURE_VideoEvent(bool pressed) {
00596         if (!pressed)
00597                 return;
00598         if (CaptureState & CAPTURE_VIDEO) {
00599                 /* Close the video */
00600                 CaptureState &= ~((unsigned int)CAPTURE_VIDEO);
00601                 LOG_MSG("Stopped capturing video.");    
00602 
00603                 if (capture.video.writer != NULL) {
00604                         if ( capture.video.audioused ) {
00605                                 CAPTURE_AddAviChunk( "01wb", (Bit32u)(capture.video.audioused * 4), capture.video.audiobuf, 0x10, 1);
00606                                 capture.video.audiowritten = capture.video.audioused*4;
00607                                 capture.video.audioused = 0;
00608                         }
00609 
00610                         avi_writer_end_data(capture.video.writer);
00611                         avi_writer_finish(capture.video.writer);
00612                         avi_writer_close_file(capture.video.writer);
00613                         capture.video.writer = avi_writer_destroy(capture.video.writer);
00614                 }
00615 #if (C_AVCODEC)
00616                 if (ffmpeg_fmt_ctx != NULL) {
00617                         ffmpeg_flushout();
00618                         ffmpeg_closeall();
00619                 }
00620 #endif
00621 
00622                 if (capture.video.buf != NULL) {
00623                         free( capture.video.buf );
00624                         capture.video.buf = NULL;
00625                 }
00626 
00627                 if (capture.video.codec != NULL) {
00628                         delete capture.video.codec;
00629                         capture.video.codec = NULL;
00630                 }
00631         } else {
00632                 CaptureState |= CAPTURE_VIDEO;
00633         }
00634 
00635         mainMenu.get_item("mapper_video").check(!!(CaptureState & CAPTURE_VIDEO)).refresh_item(mainMenu);
00636 }
00637 #endif
00638 
00639 void CAPTURE_StartCapture(void) {
00640 #if (C_SSHOT)
00641         if (!(CaptureState & CAPTURE_VIDEO))
00642         CAPTURE_VideoEvent(true);
00643 #endif
00644 }
00645 
00646 void CAPTURE_StopCapture(void) {
00647 #if (C_SSHOT)
00648         if (CaptureState & CAPTURE_VIDEO)
00649         CAPTURE_VideoEvent(true);
00650 #endif
00651 }
00652 
00653 #if !defined(C_EMSCRIPTEN)
00654 void CAPTURE_WaveEvent(bool pressed);
00655 #endif
00656 
00657 void CAPTURE_StartWave(void) {
00658 #if !defined(C_EMSCRIPTEN)
00659         if (!(CaptureState & CAPTURE_WAVE))
00660         CAPTURE_WaveEvent(true);
00661 #endif
00662 }
00663 
00664 void CAPTURE_StopWave(void) {
00665 #if !defined(C_EMSCRIPTEN)
00666         if (CaptureState & CAPTURE_WAVE)
00667         CAPTURE_WaveEvent(true);
00668 #endif
00669 }
00670 
00671 #if !defined(C_EMSCRIPTEN)
00672 void CAPTURE_MTWaveEvent(bool pressed);
00673 #endif
00674 
00675 void CAPTURE_StartMTWave(void) {
00676 #if !defined(C_EMSCRIPTEN)
00677         if (!(CaptureState & CAPTURE_MULTITRACK_WAVE))
00678         CAPTURE_MTWaveEvent(true);
00679 #endif
00680 }
00681 
00682 void CAPTURE_StopMTWave(void) {
00683 #if !defined(C_EMSCRIPTEN)
00684         if (CaptureState & CAPTURE_MULTITRACK_WAVE)
00685         CAPTURE_MTWaveEvent(true);
00686 #endif
00687 }
00688 
00689 #if (C_SSHOT)
00690 extern uint32_t GFX_palette32bpp[256];
00691 #endif
00692 
00693 unsigned int GFX_GetBShift();
00694 
00695 void CAPTURE_AddImage(Bitu width, Bitu height, Bitu bpp, Bitu pitch, Bitu flags, float fps, Bit8u * data, Bit8u * pal) {
00696 #if (C_SSHOT)
00697         Bitu i;
00698         Bit8u doubleRow[SCALER_MAXWIDTH*4];
00699         Bitu countWidth = width;
00700 
00701         if (flags & CAPTURE_FLAG_DBLH)
00702                 height *= 2;
00703         if (flags & CAPTURE_FLAG_DBLW)
00704                 width *= 2;
00705 
00706         if (height > SCALER_MAXHEIGHT)
00707                 return;
00708         if (width > SCALER_MAXWIDTH)
00709                 return;
00710         
00711         if (CaptureState & CAPTURE_IMAGE) {
00712                 png_structp png_ptr;
00713                 png_infop info_ptr;
00714                 png_color palette[256];
00715 
00716                 CaptureState &= ~((unsigned int)CAPTURE_IMAGE);
00717                 /* Open the actual file */
00718                 FILE * fp=OpenCaptureFile("Screenshot",".png");
00719                 if (!fp) goto skip_shot;
00720                 /* First try to allocate the png structures */
00721                 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,NULL, NULL);
00722                 if (!png_ptr) goto skip_shot;
00723                 info_ptr = png_create_info_struct(png_ptr);
00724                 if (!info_ptr) {
00725                         png_destroy_write_struct(&png_ptr,(png_infopp)NULL);
00726                         goto skip_shot;
00727                 }
00728         
00729                 /* Finalize the initing of png library */
00730                 png_init_io(png_ptr, fp);
00731                 png_set_compression_level(png_ptr,Z_BEST_COMPRESSION);
00732                 
00733                 /* set other zlib parameters */
00734                 png_set_compression_mem_level(png_ptr, 8);
00735                 png_set_compression_strategy(png_ptr,Z_DEFAULT_STRATEGY);
00736                 png_set_compression_window_bits(png_ptr, 15);
00737                 png_set_compression_method(png_ptr, 8);
00738                 png_set_compression_buffer_size(png_ptr, 8192);
00739         
00740                 if (bpp==8) {
00741                         png_set_IHDR(png_ptr, info_ptr, (png_uint_32)width, (png_uint_32)height,
00742                                 8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE,
00743                                 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
00744                         for (i=0;i<256;i++) {
00745                                 palette[i].red=pal[i*4+0];
00746                                 palette[i].green=pal[i*4+1];
00747                                 palette[i].blue=pal[i*4+2];
00748                         }
00749                         png_set_PLTE(png_ptr, info_ptr, palette,256);
00750                 } else {
00751                         png_set_bgr( png_ptr );
00752                         png_set_IHDR(png_ptr, info_ptr, (png_uint_32)width, (png_uint_32)height,
00753                                 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
00754                                 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
00755                 }
00756 #ifdef PNG_TEXT_SUPPORTED
00757                 int fields = 1;
00758                 png_text text[1] = {};
00759                 const char* text_s = "DOSBox " VERSION;
00760                 size_t strl = strlen(text_s);
00761                 char* ptext_s = new char[strl + 1];
00762                 strcpy(ptext_s, text_s);
00763                 char software[9] = { 'S','o','f','t','w','a','r','e',0};
00764                 text[0].compression = PNG_TEXT_COMPRESSION_NONE;
00765                 text[0].key  = software;
00766                 text[0].text = ptext_s;
00767                 png_set_text(png_ptr, info_ptr, text, fields);
00768 #endif
00769                 png_write_info(png_ptr, info_ptr);
00770 #ifdef PNG_TEXT_SUPPORTED
00771                 delete [] ptext_s;
00772 #endif
00773                 for (i=0;i<height;i++) {
00774                         void *rowPointer;
00775                         void *srcLine;
00776                         if (flags & CAPTURE_FLAG_DBLH)
00777                                 srcLine=(data+(i >> 1)*pitch);
00778                         else
00779                                 srcLine=(data+(i >> 0)*pitch);
00780                         rowPointer=srcLine;
00781                         switch (bpp) {
00782                         case 8:
00783                                 if (flags & CAPTURE_FLAG_DBLW) {
00784                                         for (Bitu x=0;x<countWidth;x++)
00785                                                 doubleRow[x*2+0] =
00786                                                 doubleRow[x*2+1] = ((Bit8u *)srcLine)[x];
00787                                         rowPointer = doubleRow;
00788                                 }
00789                                 break;
00790                         case 15:
00791                                 if (flags & CAPTURE_FLAG_DBLW) {
00792                                         for (Bitu x=0;x<countWidth;x++) {
00793                                                 Bitu pixel = ((Bit16u *)srcLine)[x];
00794                                                 doubleRow[x*6+0] = doubleRow[x*6+3] = ((pixel& 0x001f) * 0x21) >>  2;
00795                                                 doubleRow[x*6+1] = doubleRow[x*6+4] = (Bit8u)(((pixel& 0x03e0) * 0x21) >> 7);
00796                                                 doubleRow[x*6+2] = doubleRow[x*6+5] = ((pixel& 0x7c00) * 0x21) >>  12;
00797                                         }
00798                                 } else {
00799                                         for (Bitu x=0;x<countWidth;x++) {
00800                                                 Bitu pixel = ((Bit16u *)srcLine)[x];
00801                                                 doubleRow[x*3+0] = ((pixel& 0x001f) * 0x21) >>  2;
00802                                                 doubleRow[x*3+1] = (Bit8u)(((pixel& 0x03e0) * 0x21) >> 7);
00803                                                 doubleRow[x*3+2] = ((pixel& 0x7c00) * 0x21) >>  12;
00804                                         }
00805                                 }
00806                                 rowPointer = doubleRow;
00807                                 break;
00808                         case 16:
00809                                 if (flags & CAPTURE_FLAG_DBLW) {
00810                                         for (Bitu x=0;x<countWidth;x++) {
00811                                                 Bitu pixel = ((Bit16u *)srcLine)[x];
00812                                                 doubleRow[x*6+0] = doubleRow[x*6+3] = ((pixel& 0x001f) * 0x21) >> 2;
00813                                                 doubleRow[x*6+1] = doubleRow[x*6+4] = ((pixel& 0x07e0) * 0x41) >> 9;
00814                                                 doubleRow[x*6+2] = doubleRow[x*6+5] = ((pixel& 0xf800) * 0x21) >> 13;
00815                                         }
00816                                 } else {
00817                                         for (Bitu x=0;x<countWidth;x++) {
00818                                                 Bitu pixel = ((Bit16u *)srcLine)[x];
00819                                                 doubleRow[x*3+0] = ((pixel& 0x001f) * 0x21) >>  2;
00820                                                 doubleRow[x*3+1] = ((pixel& 0x07e0) * 0x41) >>  9;
00821                                                 doubleRow[x*3+2] = ((pixel& 0xf800) * 0x21) >>  13;
00822                                         }
00823                                 }
00824                                 rowPointer = doubleRow;
00825                                 break;
00826                         case 32:
00827                                 if (flags & CAPTURE_FLAG_DBLW) {
00828                                         for (Bitu x=0;x<countWidth;x++) {
00829                                                 doubleRow[x*6+0] = doubleRow[x*6+3] = ((Bit8u *)srcLine)[x*4+0];
00830                                                 doubleRow[x*6+1] = doubleRow[x*6+4] = ((Bit8u *)srcLine)[x*4+1];
00831                                                 doubleRow[x*6+2] = doubleRow[x*6+5] = ((Bit8u *)srcLine)[x*4+2];
00832                                         }
00833                                 } else {
00834                                         for (Bitu x=0;x<countWidth;x++) {
00835                                                 doubleRow[x*3+0] = ((Bit8u *)srcLine)[x*4+0];
00836                                                 doubleRow[x*3+1] = ((Bit8u *)srcLine)[x*4+1];
00837                                                 doubleRow[x*3+2] = ((Bit8u *)srcLine)[x*4+2];
00838                                         }
00839                                 }
00840                                 rowPointer = doubleRow;
00841                                 break;
00842                         }
00843                         png_write_row(png_ptr, (png_bytep)rowPointer);
00844                 }
00845                 /* Finish writing */
00846                 png_write_end(png_ptr, 0);
00847                 /*Destroy PNG structs*/
00848                 png_destroy_write_struct(&png_ptr, &info_ptr);
00849                 /*close file*/
00850                 fclose(fp);
00851         }
00852 skip_shot:
00853         if (CaptureState & CAPTURE_VIDEO) {
00854                 zmbv_format_t format;
00855                 /* Disable capturing if any of the test fails */
00856                 if (capture.video.width != width ||
00857                         capture.video.height != height ||
00858                         capture.video.bpp != bpp ||
00859                         capture.video.fps != fps) {
00860                         if (native_zmbv && capture.video.writer != NULL)
00861                                 CAPTURE_VideoEvent(true);
00862 #if (C_AVCODEC)
00863                         else if (export_ffmpeg && ffmpeg_fmt_ctx != NULL) {
00864                                 ffmpeg_flush_video();
00865                                 ffmpeg_video_frame_time_offset += ffmpeg_video_frame_last_time;
00866                                 ffmpeg_video_frame_last_time = 0;
00867 
00868                                 capture.video.width = width;
00869                                 capture.video.height = height;
00870                                 capture.video.bpp = bpp;
00871                                 capture.video.fps = fps;
00872                                 capture.video.frames = 0;
00873 
00874                                 ffmpeg_reopen_video(fps,(int)bpp);
00875 //                              CAPTURE_VideoEvent(true);
00876                         }
00877 #endif
00878                 }
00879 
00880                 CaptureState &= ~((unsigned int)CAPTURE_VIDEO);
00881 
00882                 switch (bpp) {
00883                 case 8:format = ZMBV_FORMAT_8BPP;break;
00884                 case 15:format = ZMBV_FORMAT_15BPP;break;
00885                 case 16:format = ZMBV_FORMAT_16BPP;break;
00886                 case 32:format = ZMBV_FORMAT_32BPP;break;
00887                 default:
00888                         goto skip_video;
00889                 }
00890 
00891                 if (native_zmbv && capture.video.writer == NULL) {
00892                         std::string path = GetCaptureFilePath("Video",".avi");
00893                         if (path == "")
00894                                 goto skip_video;
00895 
00896                         capture.video.writer = avi_writer_create();
00897                         if (capture.video.writer == NULL)
00898                                 goto skip_video;
00899 
00900                         if (!avi_writer_open_file(capture.video.writer,path.c_str()))
00901                                 goto skip_video;
00902 
00903             if (!avi_writer_set_stream_writing(capture.video.writer))
00904                 goto skip_video;
00905 
00906                         capture.video.codec = new VideoCodec();
00907                         if (!capture.video.codec)
00908                                 goto skip_video;
00909                         if (!capture.video.codec->SetupCompress( (int)width, (int)height)) 
00910                                 goto skip_video;
00911                         capture.video.bufSize = capture.video.codec->NeededSize((int)width, (int)height, format);
00912                         capture.video.buf = malloc( (size_t)capture.video.bufSize );
00913                         if (!capture.video.buf)
00914                                 goto skip_video;
00915 
00916                         capture.video.width = width;
00917                         capture.video.height = height;
00918                         capture.video.bpp = bpp;
00919                         capture.video.fps = fps;
00920                         capture.video.frames = 0;
00921                         capture.video.written = 0;
00922                         capture.video.audioused = 0;
00923                         capture.video.audiowritten = 0;
00924 
00925                         riff_avih_AVIMAINHEADER *mheader = avi_writer_main_header(capture.video.writer);
00926                         if (mheader == NULL)
00927                                 goto skip_video;
00928 
00929                         memset(mheader,0,sizeof(*mheader));
00930                         __w_le_u32(&mheader->dwMicroSecPerFrame,(uint32_t)(1000000 / fps)); /* NTS: int divided by double */
00931                         __w_le_u32(&mheader->dwMaxBytesPerSec,0);
00932                         __w_le_u32(&mheader->dwPaddingGranularity,0);
00933                         __w_le_u32(&mheader->dwFlags,0x110);                     /* Flags,0x10 has index, 0x100 interleaved */
00934                         __w_le_u32(&mheader->dwTotalFrames,0);                  /* AVI writer updates this automatically on finish */
00935                         __w_le_u32(&mheader->dwInitialFrames,0);
00936                         __w_le_u32(&mheader->dwStreams,2);                      /* audio+video */
00937                         __w_le_u32(&mheader->dwSuggestedBufferSize,0);
00938                         __w_le_u32(&mheader->dwWidth,(uint32_t)capture.video.width);
00939                         __w_le_u32(&mheader->dwHeight,(uint32_t)capture.video.height);
00940 
00941 
00942 
00943                         avi_writer_stream *vstream = avi_writer_new_stream(capture.video.writer);
00944                         if (vstream == NULL)
00945                                 goto skip_video;
00946 
00947                         riff_strh_AVISTREAMHEADER *vsheader = avi_writer_stream_header(vstream);
00948                         if (vsheader == NULL)
00949                                 goto skip_video;
00950 
00951                         memset(vsheader,0,sizeof(*vsheader));
00952                         __w_le_u32(&vsheader->fccType,avi_fccType_video);
00953                         __w_le_u32(&vsheader->fccHandler,avi_fourcc_const('Z','M','B','V'));
00954                         __w_le_u32(&vsheader->dwFlags,0);
00955                         __w_le_u16(&vsheader->wPriority,0);
00956                         __w_le_u16(&vsheader->wLanguage,0);
00957                         __w_le_u32(&vsheader->dwInitialFrames,0);
00958                         __w_le_u32(&vsheader->dwScale,1000000);
00959                         __w_le_u32(&vsheader->dwRate,(uint32_t)(1000000 * fps));
00960                         __w_le_u32(&vsheader->dwStart,0);
00961                         __w_le_u32(&vsheader->dwLength,0);                      /* AVI writer updates this automatically */
00962                         __w_le_u32(&vsheader->dwSuggestedBufferSize,0);
00963                         __w_le_u32(&vsheader->dwQuality,~0u);
00964                         __w_le_u32(&vsheader->dwSampleSize,0u);
00965                         __w_le_u16(&vsheader->rcFrame.left,0);
00966                         __w_le_u16(&vsheader->rcFrame.top,0);
00967                         __w_le_u16(&vsheader->rcFrame.right,(uint16_t)capture.video.width);
00968                         __w_le_u16(&vsheader->rcFrame.bottom,(uint16_t)capture.video.height);
00969 
00970                         windows_BITMAPINFOHEADER vbmp;
00971 
00972                         memset(&vbmp,0,sizeof(vbmp));
00973                         __w_le_u32(&vbmp.biSize,sizeof(vbmp)); /* 40 */
00974                         __w_le_u32(&vbmp.biWidth,(uint32_t)capture.video.width);
00975                         __w_le_u32(&vbmp.biHeight,(uint32_t)capture.video.height);
00976                         __w_le_u16(&vbmp.biPlanes,0);           /* FIXME: Only repeating what the original DOSBox code did */
00977                         __w_le_u16(&vbmp.biBitCount,0);         /* FIXME: Only repeating what the original DOSBox code did */
00978                         __w_le_u32(&vbmp.biCompression,avi_fourcc_const('Z','M','B','V'));
00979                         __w_le_u32(&vbmp.biSizeImage,(uint32_t)(capture.video.width * capture.video.height * 4));
00980 
00981                         if (!avi_writer_stream_set_format(vstream,&vbmp,sizeof(vbmp)))
00982                                 goto skip_video;
00983 
00984 
00985                         avi_writer_stream *astream = avi_writer_new_stream(capture.video.writer);
00986                         if (astream == NULL)
00987                                 goto skip_video;
00988 
00989                         riff_strh_AVISTREAMHEADER *asheader = avi_writer_stream_header(astream);
00990                         if (asheader == NULL)
00991                                 goto skip_video;
00992 
00993                         memset(asheader,0,sizeof(*asheader));
00994                         __w_le_u32(&asheader->fccType,avi_fccType_audio);
00995                         __w_le_u32(&asheader->fccHandler,0);
00996                         __w_le_u32(&asheader->dwFlags,0);
00997                         __w_le_u16(&asheader->wPriority,0);
00998                         __w_le_u16(&asheader->wLanguage,0);
00999                         __w_le_u32(&asheader->dwInitialFrames,0);
01000                         __w_le_u32(&asheader->dwScale,1);
01001                         __w_le_u32(&asheader->dwRate,(uint32_t)capture.video.audiorate);
01002                         __w_le_u32(&asheader->dwStart,0);
01003                         __w_le_u32(&asheader->dwLength,0);                      /* AVI writer updates this automatically */
01004                         __w_le_u32(&asheader->dwSuggestedBufferSize,0);
01005                         __w_le_u32(&asheader->dwQuality,~0u);
01006                         __w_le_u32(&asheader->dwSampleSize,2*2);
01007                         __w_le_u16(&asheader->rcFrame.left,0);
01008                         __w_le_u16(&asheader->rcFrame.top,0);
01009                         __w_le_u16(&asheader->rcFrame.right,0);
01010                         __w_le_u16(&asheader->rcFrame.bottom,0);
01011 
01012                         windows_WAVEFORMAT fmt;
01013 
01014                         memset(&fmt,0,sizeof(fmt));
01015                         __w_le_u16(&fmt.wFormatTag,windows_WAVE_FORMAT_PCM);
01016                         __w_le_u16(&fmt.nChannels,2);                   /* stereo */
01017                         __w_le_u32(&fmt.nSamplesPerSec,(uint32_t)capture.video.audiorate);
01018                         __w_le_u16(&fmt.wBitsPerSample,16);             /* 16-bit/sample */
01019                         __w_le_u16(&fmt.nBlockAlign,2*2);
01020                         __w_le_u32(&fmt.nAvgBytesPerSec,(uint32_t)(capture.video.audiorate*2*2));
01021 
01022                         if (!avi_writer_stream_set_format(astream,&fmt,sizeof(fmt)))
01023                                 goto skip_video;
01024 
01025                         if (!avi_writer_begin_header(capture.video.writer) || !avi_writer_begin_data(capture.video.writer))
01026                                 goto skip_video;
01027 
01028                         LOG_MSG("Started capturing video.");
01029                 }
01030 #if (C_AVCODEC)
01031                 else if (export_ffmpeg && ffmpeg_fmt_ctx == NULL) {
01032                         std::string path = GetCaptureFilePath("Video",".mts"); // Use widely recognized .MTS extension
01033                         if (path == "")
01034                                 goto skip_video;
01035 
01036                         capture.video.width = width;
01037                         capture.video.height = height;
01038                         capture.video.bpp = bpp;
01039                         capture.video.fps = fps;
01040                         capture.video.frames = 0;
01041                         capture.video.written = 0;
01042                         capture.video.audioused = 0;
01043                         capture.video.audiowritten = 0;
01044                         ffmpeg_audio_sample_counter = 0;
01045 
01046                         if (!ffmpeg_init) {
01047                                 LOG_MSG("Attempting to initialize FFMPEG library");
01048                                 ffmpeg_init = true;
01049                         }
01050 
01051                         ffmpeg_aud_codec = avcodec_find_encoder(AV_CODEC_ID_AAC);
01052                         ffmpeg_vid_codec = avcodec_find_encoder(AV_CODEC_ID_H264);
01053                         if (ffmpeg_aud_codec == NULL || ffmpeg_vid_codec == NULL) {
01054                                 LOG_MSG("H.264 or AAC encoder not available");
01055                                 goto skip_video;
01056                         }
01057 
01058                         if (avformat_alloc_output_context2(&ffmpeg_fmt_ctx,NULL,"mpegts",NULL) < 0) {
01059                                 LOG_MSG("Failed to allocate format context (mpegts)");
01060                                 goto skip_video;
01061                         }
01062                         snprintf(ffmpeg_fmt_ctx->filename,sizeof(ffmpeg_fmt_ctx->filename),"%s",path.c_str());
01063 
01064                         if (ffmpeg_fmt_ctx->oformat == NULL)
01065                                 goto skip_video;
01066 
01067                         if (avio_open(&ffmpeg_fmt_ctx->pb,ffmpeg_fmt_ctx->filename,AVIO_FLAG_WRITE) < 0) {
01068                                 LOG_MSG("Failed to avio_open");
01069                                 goto skip_video;
01070                         }
01071 
01072                         ffmpeg_vid_stream = avformat_new_stream(ffmpeg_fmt_ctx,ffmpeg_vid_codec);
01073                         if (ffmpeg_vid_stream == NULL) {
01074                                 LOG_MSG("failed to open audio stream");
01075                                 goto skip_video;
01076                         }
01077                         ffmpeg_vid_ctx = ffmpeg_vid_stream->codec;
01078                         avcodec_get_context_defaults3(ffmpeg_vid_ctx,ffmpeg_vid_codec);
01079                         ffmpeg_vid_ctx->bit_rate = 25000000; // TODO: make configuration option!
01080                         ffmpeg_vid_ctx->keyint_min = 15; // TODO: make configuration option!
01081                         ffmpeg_vid_ctx->time_base.num = 1000000;
01082                         ffmpeg_vid_ctx->time_base.den = (int)(1000000 * fps);
01083                         ffmpeg_vid_ctx->width = (int)capture.video.width;
01084                         ffmpeg_vid_ctx->height = (int)capture.video.height;
01085                         ffmpeg_vid_ctx->gop_size = 15; // TODO: make config option
01086                         ffmpeg_vid_ctx->max_b_frames = 0;
01087                         ffmpeg_vid_ctx->pix_fmt = ffmpeg_choose_pixfmt(ffmpeg_yuv_format_choice); // TODO: auto-choose according to what codec says is supported, and let user choose as well
01088                         ffmpeg_vid_ctx->thread_count = 0;               // auto-choose
01089                         ffmpeg_vid_ctx->flags2 = AV_CODEC_FLAG2_FAST;
01090                         ffmpeg_vid_ctx->qmin = 1;
01091                         ffmpeg_vid_ctx->qmax = 63;
01092                         ffmpeg_vid_ctx->rc_max_rate = ffmpeg_vid_ctx->bit_rate;
01093                         ffmpeg_vid_ctx->rc_min_rate = ffmpeg_vid_ctx->bit_rate;
01094                         ffmpeg_vid_ctx->rc_buffer_size = (4*1024*1024);
01095 
01096                         /* 4:3 aspect ratio. FFMPEG thinks in terms of Pixel Aspect Ratio not Display Aspect Ratio */
01097                         ffmpeg_vid_ctx->sample_aspect_ratio.num = 4 * (int)capture.video.height;
01098                         ffmpeg_vid_ctx->sample_aspect_ratio.den = 3 * (int)capture.video.width;
01099 
01100                         {
01101                                 AVDictionary *opts = NULL;
01102 
01103                                 av_dict_set(&opts,"preset","superfast",1);
01104                                 av_dict_set(&opts,"aud","1",1);
01105 
01106                                 if (avcodec_open2(ffmpeg_vid_ctx,ffmpeg_vid_codec,&opts) < 0) {
01107                                         LOG_MSG("Unable to open H.264 codec");
01108                                         goto skip_video;
01109                                 }
01110 
01111                                 av_dict_free(&opts);
01112                         }
01113 
01114                         ffmpeg_vid_stream->time_base.num = (int)1000000;
01115                         ffmpeg_vid_stream->time_base.den = (int)(1000000 * fps);
01116 
01117                         ffmpeg_aud_stream = avformat_new_stream(ffmpeg_fmt_ctx,ffmpeg_aud_codec);
01118                         if (ffmpeg_aud_stream == NULL) {
01119                                 LOG_MSG("failed to open audio stream");
01120                                 goto skip_video;
01121                         }
01122                         ffmpeg_aud_ctx = ffmpeg_aud_stream->codec;
01123                         avcodec_get_context_defaults3(ffmpeg_aud_ctx,ffmpeg_aud_codec);
01124                         ffmpeg_aud_ctx->sample_rate = (int)capture.video.audiorate;
01125                         ffmpeg_aud_ctx->channels = 2;
01126                         ffmpeg_aud_ctx->flags = 0; // do not use global headers
01127                         ffmpeg_aud_ctx->bit_rate = 320000;
01128                         ffmpeg_aud_ctx->profile = FF_PROFILE_AAC_LOW;
01129                         ffmpeg_aud_ctx->channel_layout = AV_CH_LAYOUT_STEREO;
01130 
01131                         if (ffmpeg_aud_codec->sample_fmts != NULL)
01132                                 ffmpeg_aud_ctx->sample_fmt = (ffmpeg_aud_codec->sample_fmts)[0];
01133                         else
01134                                 ffmpeg_aud_ctx->sample_fmt = AV_SAMPLE_FMT_FLT;
01135 
01136                         if (avcodec_open2(ffmpeg_aud_ctx,ffmpeg_aud_codec,NULL) < 0) {
01137                                 LOG_MSG("Failed to open audio codec");
01138                                 goto skip_video;
01139                         }
01140 
01141                         ffmpeg_aud_stream->time_base.num = 1;
01142                         ffmpeg_aud_stream->time_base.den = ffmpeg_aud_ctx->sample_rate;
01143 
01144                         /* Note whether we started the header.
01145                          * Writing the trailer out of turn seems to cause segfaults in libavformat */
01146                         ffmpeg_avformat_began = true;
01147 
01148                         if (avformat_write_header(ffmpeg_fmt_ctx,NULL) < 0) {
01149                                 LOG_MSG("Failed to write header");
01150                                 goto skip_video;
01151                         }
01152 
01153                         ffmpeg_aud_write = 0;
01154                         ffmpeg_aud_frame = av_frame_alloc();
01155                         ffmpeg_vid_frame = av_frame_alloc();
01156                         ffmpeg_vidrgb_frame = av_frame_alloc();
01157                         if (ffmpeg_aud_frame == NULL || ffmpeg_vid_frame == NULL || ffmpeg_vidrgb_frame == NULL)
01158                                 goto skip_video;
01159 
01160                         av_frame_set_channels(ffmpeg_aud_frame,2);
01161                         av_frame_set_sample_rate(ffmpeg_aud_frame,(int)capture.video.audiorate);
01162                         av_frame_set_channel_layout(ffmpeg_aud_frame,AV_CH_LAYOUT_STEREO);
01163                         ffmpeg_aud_frame->nb_samples = ffmpeg_aud_ctx->frame_size;
01164                         ffmpeg_aud_frame->format = ffmpeg_aud_ctx->sample_fmt;
01165                         if (av_frame_get_buffer(ffmpeg_aud_frame,16) < 0) {
01166                                 LOG_MSG("Failed to alloc audio frame buffer");
01167                                 goto skip_video;
01168                         }
01169 
01170                         av_frame_set_colorspace(ffmpeg_vidrgb_frame,AVCOL_SPC_RGB);
01171                         ffmpeg_vidrgb_frame->width = (int)capture.video.width;
01172                         ffmpeg_vidrgb_frame->height = (int)capture.video.height;
01173                         ffmpeg_vidrgb_frame->format = ffmpeg_bpp_pick_rgb_format((int)bpp);
01174                         if (av_frame_get_buffer(ffmpeg_vidrgb_frame,64) < 0) {
01175                                 LOG_MSG("Failed to alloc videorgb frame buffer");
01176                                 goto skip_video;
01177                         }
01178 
01179                         av_frame_set_colorspace(ffmpeg_vid_frame,AVCOL_SPC_SMPTE170M);
01180                         av_frame_set_color_range(ffmpeg_vidrgb_frame,AVCOL_RANGE_MPEG);
01181                         ffmpeg_vid_frame->width = (int)capture.video.width;
01182                         ffmpeg_vid_frame->height = (int)capture.video.height;
01183                         ffmpeg_vid_frame->format = ffmpeg_vid_ctx->pix_fmt;
01184                         if (av_frame_get_buffer(ffmpeg_vid_frame,64) < 0) {
01185                                 LOG_MSG("Failed to alloc video frame buffer");
01186                                 goto skip_video;
01187                         }
01188 
01189                         ffmpeg_sws_ctx = sws_getContext(
01190                                 // source
01191                                 ffmpeg_vidrgb_frame->width,
01192                                 ffmpeg_vidrgb_frame->height,
01193                                 (AVPixelFormat)ffmpeg_vidrgb_frame->format,
01194                                 // dest
01195                                 ffmpeg_vid_frame->width,
01196                                 ffmpeg_vid_frame->height,
01197                                 (AVPixelFormat)ffmpeg_vid_frame->format,
01198                                 // and the rest
01199                                 ((ffmpeg_vid_frame->width == ffmpeg_vidrgb_frame->width && ffmpeg_vid_frame->height == ffmpeg_vidrgb_frame->height) ? SWS_POINT : SWS_BILINEAR),
01200                                 NULL,NULL,NULL);
01201                         if (ffmpeg_sws_ctx == NULL) {
01202                                 LOG_MSG("Failed to init colorspace conversion");
01203                                 goto skip_video;
01204                         }
01205 
01206                         LOG_MSG("Started capturing video (FFMPEG)");
01207                 }
01208 #endif
01209 
01210                 if (native_zmbv) {
01211                         int codecFlags;
01212 
01213                         if (capture.video.frames % 300 == 0)
01214                                 codecFlags = 1;
01215                         else
01216                                 codecFlags = 0;
01217 
01218             if ((flags & CAPTURE_FLAG_NOCHANGE) && skip_encoding_unchanged_frames) {
01219                 /* advance unless at keyframe */
01220                 if (codecFlags == 0) capture.video.frames++;
01221 
01222                 /* write null non-keyframe */
01223                 CAPTURE_AddAviChunk( "00dc", (Bit32u)0, capture.video.buf, (Bit32u)(0x0), 0u);
01224             }
01225             else {
01226                 if (!capture.video.codec->PrepareCompressFrame( codecFlags, format, (char *)pal, capture.video.buf, capture.video.bufSize))
01227                     goto skip_video;
01228 
01229                 for (i=0;i<height;i++) {
01230                     void * rowPointer;
01231                     if (flags & CAPTURE_FLAG_DBLW) {
01232                         void *srcLine;
01233                         Bitu x;
01234                         Bitu countWidth = width >> 1;
01235                         if (flags & CAPTURE_FLAG_DBLH)
01236                             srcLine=(data+(i >> 1)*pitch);
01237                         else
01238                             srcLine=(data+(i >> 0)*pitch);
01239                         switch ( bpp) {
01240                             case 8:
01241                                 for (x=0;x<countWidth;x++)
01242                                     ((Bit8u *)doubleRow)[x*2+0] =
01243                                         ((Bit8u *)doubleRow)[x*2+1] = ((Bit8u *)srcLine)[x];
01244                                 break;
01245                             case 15:
01246                             case 16:
01247                                 for (x=0;x<countWidth;x++)
01248                                     ((Bit16u *)doubleRow)[x*2+0] =
01249                                         ((Bit16u *)doubleRow)[x*2+1] = ((Bit16u *)srcLine)[x];
01250                                 break;
01251                             case 32:
01252                                 for (x=0;x<countWidth;x++)
01253                                     ((Bit32u *)doubleRow)[x*2+0] =
01254                                         ((Bit32u *)doubleRow)[x*2+1] = ((Bit32u *)srcLine)[x];
01255                                 break;
01256                         }
01257                         rowPointer=doubleRow;
01258                     } else {
01259                         if (flags & CAPTURE_FLAG_DBLH)
01260                             rowPointer=(data+(i >> 1)*pitch);
01261                         else
01262                             rowPointer=(data+(i >> 0)*pitch);
01263                     }
01264                     capture.video.codec->CompressLines( 1, &rowPointer );
01265                 }
01266 
01267                 int written = capture.video.codec->FinishCompressFrame();
01268                 if (written < 0)
01269                     goto skip_video;
01270 
01271                 CAPTURE_AddAviChunk( "00dc", (Bit32u)written, capture.video.buf, (Bit32u)(codecFlags & 1 ? 0x10 : 0x0), 0u);
01272                 capture.video.frames++;
01273             }
01274 
01275                         if ( capture.video.audioused ) {
01276                                 CAPTURE_AddAviChunk( "01wb", (Bit32u)(capture.video.audioused * 4u), capture.video.audiobuf, /*keyframe*/0x10u, 1u);
01277                                 capture.video.audiowritten = capture.video.audioused*4;
01278                                 capture.video.audioused = 0;
01279                         }
01280                 }
01281 #if (C_AVCODEC)
01282                 else if (export_ffmpeg && ffmpeg_fmt_ctx != NULL) {
01283                         AVPacket pkt;
01284 
01285                         // video
01286                         av_init_packet(&pkt);
01287                         if (av_new_packet(&pkt,50000000/8) == 0) {
01288                                 unsigned char *srcline,*dstline;
01289                                 Bitu x;
01290 
01291                                 // copy from source to vidrgb frame
01292                                 if (bpp == 8 && ffmpeg_vidrgb_frame->format != AV_PIX_FMT_PAL8) {
01293                                         for (i=0;i<height;i++) {
01294                                                 dstline = ffmpeg_vidrgb_frame->data[0] + ((unsigned int)i * (unsigned int)ffmpeg_vidrgb_frame->linesize[0]);
01295 
01296                                                 if (flags & CAPTURE_FLAG_DBLH)
01297                                                         srcline=(data+(i >> 1)*pitch);
01298                                                 else
01299                                                         srcline=(data+(i >> 0)*pitch);
01300 
01301                                                 if (flags & CAPTURE_FLAG_DBLW) {
01302                                                         for (x=0;x < width;x++)
01303                                                                 ((Bit32u *)dstline)[(x*2)+0] =
01304                                                                         ((Bit32u *)dstline)[(x*2)+1] = GFX_palette32bpp[srcline[x]];
01305                                                 }
01306                                                 else {
01307                                                         for (x=0;x < width;x++)
01308                                                                 ((Bit32u *)dstline)[x] = GFX_palette32bpp[srcline[x]];
01309                                                 }
01310                                         }
01311                                 }
01312                                 else {
01313                                         for (i=0;i<height;i++) {
01314                                                 dstline = ffmpeg_vidrgb_frame->data[0] + ((unsigned int)i * (unsigned int)ffmpeg_vidrgb_frame->linesize[0]);
01315 
01316                                                 if (flags & CAPTURE_FLAG_DBLW) {
01317                                                         if (flags & CAPTURE_FLAG_DBLH)
01318                                                                 srcline=(data+(i >> 1)*pitch);
01319                                                         else
01320                                                                 srcline=(data+(i >> 0)*pitch);
01321 
01322                                                         switch (bpp) {
01323                                                                 case 8:
01324                                                                         for (x=0;x<countWidth;x++)
01325                                                                                 ((Bit8u *)dstline)[x*2+0] =
01326                                                                                         ((Bit8u *)dstline)[x*2+1] = ((Bit8u *)srcline)[x];
01327                                                                         break;
01328                                                                 case 15:
01329                                                                 case 16:
01330                                                                         for (x=0;x<countWidth;x++)
01331                                                                                 ((Bit16u *)dstline)[x*2+0] =
01332                                                                                         ((Bit16u *)dstline)[x*2+1] = ((Bit16u *)srcline)[x];
01333                                                                         break;
01334                                                                 case 32:
01335                                                                         for (x=0;x<countWidth;x++)
01336                                                                                 ((Bit32u *)dstline)[x*2+0] =
01337                                                                                         ((Bit32u *)dstline)[x*2+1] = ((Bit32u *)srcline)[x];
01338                                                                         break;
01339                                                         }
01340                                                 } else {
01341                                                         if (flags & CAPTURE_FLAG_DBLH)
01342                                                                 srcline=(data+(i >> 1)*pitch);
01343                                                         else
01344                                                                 srcline=(data+(i >> 0)*pitch);
01345 
01346                                                         memcpy(dstline,srcline,width*((bpp+7)/8));
01347                                                 }
01348                                         }
01349                                 }
01350 
01351                                 // convert colorspace
01352                                 if (sws_scale(ffmpeg_sws_ctx,
01353                                         // source
01354                                         ffmpeg_vidrgb_frame->data,
01355                                         ffmpeg_vidrgb_frame->linesize,
01356                                         0,ffmpeg_vidrgb_frame->height,
01357                                         // dest
01358                                         ffmpeg_vid_frame->data,
01359                                         ffmpeg_vid_frame->linesize) <= 0)
01360                                         LOG_MSG("WARNING: sws_scale() failed");
01361 
01362                                 // encode it
01363                                 int gotit=0;
01364                                 pkt.pts = (int64_t)capture.video.frames;
01365                                 pkt.dts = (int64_t)capture.video.frames;
01366                                 ffmpeg_vid_frame->pts = (int64_t)capture.video.frames; // or else libx264 complains about non-monotonic timestamps
01367                                 ffmpeg_vid_frame->key_frame = ((capture.video.frames % 15) == 0)?1:0;
01368                                 if (avcodec_encode_video2(ffmpeg_vid_ctx,&pkt,ffmpeg_vid_frame,&gotit) == 0) {
01369                                         if (gotit) {
01370                                                 Bit64u tm;
01371 
01372                                                 tm = (Bit64u)pkt.pts;
01373                                                 pkt.stream_index = ffmpeg_vid_stream->index;
01374                                                 av_packet_rescale_ts(&pkt,ffmpeg_vid_ctx->time_base,ffmpeg_vid_stream->time_base);
01375                                                 pkt.pts += (int64_t)ffmpeg_video_frame_time_offset;
01376                                                 pkt.dts += (int64_t)ffmpeg_video_frame_time_offset;
01377 
01378                                                 if (av_interleaved_write_frame(ffmpeg_fmt_ctx,&pkt) < 0)
01379                                                         LOG_MSG("WARNING: av_interleaved_write_frame failed");
01380 
01381                                                 pkt.pts = (int64_t)tm + (int64_t)1;
01382                                                 pkt.dts = (int64_t)tm + (int64_t)1;
01383                                                 av_packet_rescale_ts(&pkt,ffmpeg_vid_ctx->time_base,ffmpeg_vid_stream->time_base);
01384                                                 ffmpeg_video_frame_last_time = (uint64_t)pkt.pts;
01385                                         }
01386                                         else {
01387                                                 LOG_MSG("DEBUG: avcodec_encode_video2 delayed frame");
01388                                                 /* delayed frame */
01389                                         }
01390                                 }
01391                                 else {
01392                                         LOG_MSG("WARNING: avcodec_encode_video2() failed");
01393                                 }
01394                         }
01395                         av_packet_unref(&pkt);
01396                         capture.video.frames++;
01397 
01398                         if ( capture.video.audioused ) {
01399                                 ffmpeg_take_audio((Bit16s*)capture.video.audiobuf/*NTS: Ewwwwww.... what if the compiler pads the 2-dimensional array?*/,capture.video.audioused);
01400                                 capture.video.audiowritten = capture.video.audioused*4;
01401                                 capture.video.audioused = 0;
01402                         }
01403                 }
01404 #endif
01405                 else {
01406                         capture.video.audiowritten = capture.video.audioused*4;
01407                         capture.video.audioused = 0;
01408                 }
01409 
01410                 /* Everything went okay, set flag again for next frame */
01411                 CaptureState |= CAPTURE_VIDEO;
01412 
01413         mainMenu.get_item("mapper_video").check(!!(CaptureState & CAPTURE_VIDEO)).refresh_item(mainMenu);
01414     }
01415 
01416         return;
01417 skip_video:
01418         capture.video.writer = avi_writer_destroy(capture.video.writer);
01419 # if (C_AVCODEC)
01420         ffmpeg_flushout();
01421         ffmpeg_closeall();
01422 # endif
01423 #endif
01424         return;
01425 }
01426 
01427 
01428 #if (C_SSHOT)
01429 void CAPTURE_ScreenShotEvent(bool pressed) {
01430         if (!pressed)
01431                 return;
01432 #if !defined(C_EMSCRIPTEN)
01433         CaptureState |= CAPTURE_IMAGE;
01434 #endif
01435 }
01436 #endif
01437 
01438 MixerChannel * MIXER_FirstChannel(void);
01439 
01440 void CAPTURE_MultiTrackAddWave(Bit32u freq, Bit32u len, Bit16s * data,const char *name) {
01441 #if !defined(C_EMSCRIPTEN)
01442     if (CaptureState & CAPTURE_MULTITRACK_WAVE) {
01443                 if (capture.multitrack_wave.writer == NULL) {
01444             unsigned int streams = 0;
01445 
01446             {
01447                 MixerChannel *c = MIXER_FirstChannel();
01448                 while (c != NULL) {
01449                     streams++;
01450                     c = c->next;
01451                 }
01452             }
01453 
01454             if (streams == 0) {
01455                 LOG_MSG("Not starting multitrack wave, no streams");
01456                 goto skip_mt_wav;
01457             }
01458 
01459                         std::string path = GetCaptureFilePath("Multitrack Wave",".mt.avi");
01460                         if (path == "") {
01461                 LOG_MSG("Cannot determine capture path");
01462                                 goto skip_mt_wav;
01463             }
01464 
01465                     capture.multitrack_wave.audiorate = freq;
01466 
01467                         capture.multitrack_wave.writer = avi_writer_create();
01468                         if (capture.multitrack_wave.writer == NULL)
01469                                 goto skip_mt_wav;
01470 
01471                         if (!avi_writer_open_file(capture.multitrack_wave.writer,path.c_str()))
01472                                 goto skip_mt_wav;
01473 
01474             if (!avi_writer_set_stream_writing(capture.multitrack_wave.writer))
01475                 goto skip_mt_wav;
01476 
01477                         riff_avih_AVIMAINHEADER *mheader = avi_writer_main_header(capture.multitrack_wave.writer);
01478                         if (mheader == NULL)
01479                                 goto skip_mt_wav;
01480 
01481                         memset(mheader,0,sizeof(*mheader));
01482                         __w_le_u32(&mheader->dwMicroSecPerFrame,(uint32_t)(1000000 / 30)); /* NTS: int divided by double FIXME GUESS */
01483                         __w_le_u32(&mheader->dwMaxBytesPerSec,0);
01484                         __w_le_u32(&mheader->dwPaddingGranularity,0);
01485                         __w_le_u32(&mheader->dwFlags,0x110);                     /* Flags,0x10 has index, 0x100 interleaved */
01486                         __w_le_u32(&mheader->dwTotalFrames,0);                  /* AVI writer updates this automatically on finish */
01487                         __w_le_u32(&mheader->dwInitialFrames,0);
01488                         __w_le_u32(&mheader->dwStreams,streams);
01489                         __w_le_u32(&mheader->dwSuggestedBufferSize,0);
01490                         __w_le_u32(&mheader->dwWidth,0);
01491                         __w_le_u32(&mheader->dwHeight,0);
01492 
01493             capture.multitrack_wave.name_to_stream_index.clear();
01494             {
01495                 MixerChannel *c = MIXER_FirstChannel();
01496                 while (c != NULL) {
01497                     /* for each channel in the mixer now, make a stream in the AVI file */
01498                     avi_writer_stream *astream = avi_writer_new_stream(capture.multitrack_wave.writer);
01499                     if (astream == NULL)
01500                         goto skip_mt_wav;
01501 
01502                     riff_strh_AVISTREAMHEADER *asheader = avi_writer_stream_header(astream);
01503                     if (asheader == NULL)
01504                         goto skip_mt_wav;
01505 
01506                     memset(asheader,0,sizeof(*asheader));
01507                     __w_le_u32(&asheader->fccType,avi_fccType_audio);
01508                     __w_le_u32(&asheader->fccHandler,0);
01509                     __w_le_u32(&asheader->dwFlags,0);
01510                     __w_le_u16(&asheader->wPriority,0);
01511                     __w_le_u16(&asheader->wLanguage,0);
01512                     __w_le_u32(&asheader->dwInitialFrames,0);
01513                     __w_le_u32(&asheader->dwScale,1);
01514                     __w_le_u32(&asheader->dwRate,(uint32_t)capture.multitrack_wave.audiorate);
01515                     __w_le_u32(&asheader->dwStart,0);
01516                     __w_le_u32(&asheader->dwLength,0);                  /* AVI writer updates this automatically */
01517                     __w_le_u32(&asheader->dwSuggestedBufferSize,0);
01518                     __w_le_u32(&asheader->dwQuality,~0u);
01519                     __w_le_u32(&asheader->dwSampleSize,2*2);
01520                     __w_le_u16(&asheader->rcFrame.left,0);
01521                     __w_le_u16(&asheader->rcFrame.top,0);
01522                     __w_le_u16(&asheader->rcFrame.right,0);
01523                     __w_le_u16(&asheader->rcFrame.bottom,0);
01524 
01525                     windows_WAVEFORMAT fmt;
01526 
01527                     memset(&fmt,0,sizeof(fmt));
01528                     __w_le_u16(&fmt.wFormatTag,windows_WAVE_FORMAT_PCM);
01529                     __w_le_u16(&fmt.nChannels,2);                       /* stereo */
01530                     __w_le_u32(&fmt.nSamplesPerSec,(uint32_t)capture.multitrack_wave.audiorate);
01531                     __w_le_u16(&fmt.wBitsPerSample,16);         /* 16-bit/sample */
01532                     __w_le_u16(&fmt.nBlockAlign,2*2);
01533                     __w_le_u32(&fmt.nAvgBytesPerSec,(uint32_t)(capture.multitrack_wave.audiorate*2*2));
01534 
01535                     if (!avi_writer_stream_set_format(astream,&fmt,sizeof(fmt)))
01536                         goto skip_mt_wav;
01537 
01538                     if (c->name != NULL && *(c->name) != 0) {
01539                                     LOG_MSG("multitrack audio, mixer channel '%s' is AVI stream %d",c->name,astream->index);
01540                         capture.multitrack_wave.name_to_stream_index[c->name] = (size_t)astream->index;
01541                         astream->name = c->name;
01542                     }
01543 
01544                     c = c->next;
01545                 }
01546             }
01547 
01548                         if (!avi_writer_begin_header(capture.multitrack_wave.writer) || !avi_writer_begin_data(capture.multitrack_wave.writer))
01549                                 goto skip_mt_wav;
01550 
01551                         LOG_MSG("Started capturing multitrack audio (%u channels).",streams);
01552                 }
01553 
01554         if (capture.multitrack_wave.writer != NULL) {
01555             std::map<std::string,size_t>::iterator ni = capture.multitrack_wave.name_to_stream_index.find(name);
01556             if (ni != capture.multitrack_wave.name_to_stream_index.end()) {
01557                 size_t index = ni->second;
01558 
01559                 if (index < (size_t)capture.multitrack_wave.writer->avi_stream_alloc) {
01560                     avi_writer_stream *os = capture.multitrack_wave.writer->avi_stream + index;
01561                                 avi_writer_stream_write(capture.multitrack_wave.writer,os,data,len * 2 * 2,/*keyframe*/0x10);
01562                 }
01563                 else {
01564                     LOG_MSG("Multitrack: Ignoring unknown track '%s', out of range\n",name);
01565                 }
01566             }
01567             else {
01568                 LOG_MSG("Multitrack: Ignoring unknown track '%s'\n",name);
01569             }
01570         }
01571     }
01572 
01573     return;
01574 skip_mt_wav:
01575         capture.multitrack_wave.writer = avi_writer_destroy(capture.multitrack_wave.writer);
01576 #endif
01577 }
01578 
01579 void CAPTURE_AddWave(Bit32u freq, Bit32u len, Bit16s * data) {
01580 #if !defined(C_EMSCRIPTEN)
01581 #if (C_SSHOT)
01582         if (CaptureState & CAPTURE_VIDEO) {
01583                 Bitu left = WAVE_BUF - capture.video.audioused;
01584                 if (left > len)
01585                         left = len;
01586                 memcpy( &capture.video.audiobuf[capture.video.audioused], data, left*4);
01587                 capture.video.audioused += left;
01588                 capture.video.audiorate = freq;
01589         }
01590 #endif
01591         if (CaptureState & CAPTURE_WAVE) {
01592                 if (capture.wave.writer == NULL) {
01593                         std::string path = GetCaptureFilePath("Wave Output",".wav");
01594                         if (path == "") {
01595                                 CaptureState &= ~((unsigned int)CAPTURE_WAVE);
01596                                 return;
01597                         }
01598 
01599                         capture.wave.writer = riff_wav_writer_create();
01600                         if (capture.wave.writer == NULL) {
01601                                 CaptureState &= ~((unsigned int)CAPTURE_WAVE);
01602                                 capture.wave.writer = riff_wav_writer_destroy(capture.wave.writer);
01603                                 return;
01604                         }
01605 
01606                         windows_WAVEFORMAT fmt;
01607 
01608                         memset(&fmt,0,sizeof(fmt));
01609                         __w_le_u16(&fmt.wFormatTag,windows_WAVE_FORMAT_PCM);
01610                         __w_le_u16(&fmt.nChannels,2);                   /* stereo */
01611                         __w_le_u32(&fmt.nSamplesPerSec,freq);
01612                         __w_le_u16(&fmt.wBitsPerSample,16);             /* 16-bit/sample */
01613                         __w_le_u16(&fmt.nBlockAlign,2*2);
01614                         __w_le_u32(&fmt.nAvgBytesPerSec,freq*2*2);
01615 
01616                         if (!riff_wav_writer_open_file(capture.wave.writer,path.c_str())) {
01617                                 CaptureState &= ~((unsigned int)CAPTURE_WAVE);
01618                                 capture.wave.writer = riff_wav_writer_destroy(capture.wave.writer);
01619                                 return;
01620                         }
01621                         if (!riff_wav_writer_set_format(capture.wave.writer,&fmt) ||
01622                                 !riff_wav_writer_begin_header(capture.wave.writer) ||
01623                                 !riff_wav_writer_begin_data(capture.wave.writer)) {
01624                                 CaptureState &= ~((unsigned int)CAPTURE_WAVE);
01625                                 capture.wave.writer = riff_wav_writer_destroy(capture.wave.writer);
01626                                 return;
01627                         }
01628 
01629                         capture.wave.length = 0;
01630                         capture.wave.used = 0;
01631                         capture.wave.freq = freq;
01632                         LOG_MSG("Started capturing wave output.");
01633                 }
01634                 Bit16s * read = data;
01635                 while (len > 0 ) {
01636                         Bitu left = WAVE_BUF - capture.wave.used;
01637                         if (!left) {
01638                                 riff_wav_writer_data_write(capture.wave.writer,capture.wave.buf,2*2*WAVE_BUF);
01639                                 capture.wave.length += 4*WAVE_BUF;
01640                                 capture.wave.used = 0;
01641                                 left = WAVE_BUF;
01642                         }
01643                         if (left > len)
01644                                 left = len;
01645                         memcpy( &capture.wave.buf[capture.wave.used], read, left*4);
01646                         capture.wave.used += left;
01647                         read += left*2;
01648                         len -= (Bit32u)left;
01649                 }
01650         }
01651 #endif
01652 }
01653 
01654 void CAPTURE_MTWaveEvent(bool pressed) {
01655         if (!pressed)
01656                 return;
01657 
01658 #if !defined(C_EMSCRIPTEN)
01659     if (CaptureState & CAPTURE_MULTITRACK_WAVE) {
01660         if (capture.multitrack_wave.writer != NULL) {
01661             LOG_MSG("Stopped capturing multitrack wave output.");
01662             capture.multitrack_wave.name_to_stream_index.clear();
01663             avi_writer_end_data(capture.multitrack_wave.writer);
01664             avi_writer_finish(capture.multitrack_wave.writer);
01665             avi_writer_close_file(capture.multitrack_wave.writer);
01666             capture.multitrack_wave.writer = avi_writer_destroy(capture.multitrack_wave.writer);
01667             CaptureState &= ~((unsigned int)CAPTURE_MULTITRACK_WAVE);
01668         }
01669     }
01670     else {
01671         CaptureState |= CAPTURE_MULTITRACK_WAVE;
01672     }
01673 
01674         mainMenu.get_item("mapper_recmtwave").check(!!(CaptureState & CAPTURE_MULTITRACK_WAVE)).refresh_item(mainMenu);
01675 #endif
01676 }
01677 
01678 void CAPTURE_WaveEvent(bool pressed) {
01679         if (!pressed)
01680                 return;
01681 
01682 #if !defined(C_EMSCRIPTEN)
01683     if (CaptureState & CAPTURE_WAVE) {
01684         /* Check for previously opened wave file */
01685         if (capture.wave.writer != NULL) {
01686             LOG_MSG("Stopped capturing wave output.");
01687             /* Write last piece of audio in buffer */
01688             riff_wav_writer_data_write(capture.wave.writer,capture.wave.buf,2*2*capture.wave.used);
01689             capture.wave.length+=(Bit32u)(capture.wave.used*4);
01690             riff_wav_writer_end_data(capture.wave.writer);
01691             capture.wave.writer = riff_wav_writer_destroy(capture.wave.writer);
01692             CaptureState &= ~((unsigned int)CAPTURE_WAVE);
01693         }
01694     }
01695     else {
01696         CaptureState |= CAPTURE_WAVE;
01697     }
01698 
01699         mainMenu.get_item("mapper_recwave").check(!!(CaptureState & CAPTURE_WAVE)).refresh_item(mainMenu);
01700 #endif
01701 }
01702 
01703 /* MIDI capturing */
01704 
01705 static Bit8u midi_header[]={
01706         'M','T','h','d',                        /* Bit32u, Header Chunk */
01707         0x0,0x0,0x0,0x6,                        /* Bit32u, Chunk Length */
01708         0x0,0x0,                                        /* Bit16u, Format, 0=single track */
01709         0x0,0x1,                                        /* Bit16u, Track Count, 1 track */
01710         0x01,0xf4,                                      /* Bit16u, Timing, 2 beats/second with 500 frames */
01711         'M','T','r','k',                        /* Bit32u, Track Chunk */
01712         0x0,0x0,0x0,0x0,                        /* Bit32u, Chunk Length */
01713         //Track data
01714 };
01715 
01716 
01717 static void RawMidiAdd(Bit8u data) {
01718         capture.midi.buffer[capture.midi.used++]=data;
01719         if (capture.midi.used >= MIDI_BUF ) {
01720                 capture.midi.done += capture.midi.used;
01721                 fwrite(capture.midi.buffer,1,MIDI_BUF,capture.midi.handle);
01722                 capture.midi.used = 0;
01723         }
01724 }
01725 
01726 static void RawMidiAddNumber(Bit32u val) {
01727         if (val & 0xfe00000) RawMidiAdd((Bit8u)(0x80|((val >> 21) & 0x7f)));
01728         if (val & 0xfffc000) RawMidiAdd((Bit8u)(0x80|((val >> 14) & 0x7f)));
01729         if (val & 0xfffff80) RawMidiAdd((Bit8u)(0x80|((val >> 7) & 0x7f)));
01730         RawMidiAdd((Bit8u)(val & 0x7f));
01731 }
01732 
01733 void CAPTURE_AddMidi(bool sysex, Bitu len, Bit8u * data) {
01734         if (!capture.midi.handle) {
01735                 capture.midi.handle=OpenCaptureFile("Raw Midi",".mid");
01736                 if (!capture.midi.handle) {
01737                         return;
01738                 }
01739                 fwrite(midi_header,1,sizeof(midi_header),capture.midi.handle);
01740                 capture.midi.last=(Bit32u)PIC_Ticks;
01741         }
01742         Bit32u delta=(Bit32u)(PIC_Ticks-capture.midi.last);
01743         capture.midi.last=(Bit32u)PIC_Ticks;
01744         RawMidiAddNumber(delta);
01745         if (sysex) {
01746                 RawMidiAdd( 0xf0 );
01747                 RawMidiAddNumber((Bit32u)len);
01748         }
01749         for (Bitu i=0;i<len;i++) 
01750                 RawMidiAdd(data[i]);
01751 }
01752 
01753 void CAPTURE_MidiEvent(bool pressed) {
01754         if (!pressed)
01755                 return;
01756         /* Check for previously opened wave file */
01757         if (capture.midi.handle) {
01758                 LOG_MSG("Stopping raw midi saving and finalizing file.");
01759                 //Delta time
01760                 RawMidiAdd(0x00);
01761                 //End of track event
01762                 RawMidiAdd(0xff);
01763                 RawMidiAdd(0x2F);
01764                 RawMidiAdd(0x00);
01765                 /* clear out the final data in the buffer if any */
01766                 fwrite(capture.midi.buffer,1,capture.midi.used,capture.midi.handle);
01767                 capture.midi.done+=capture.midi.used;
01768                 fseek(capture.midi.handle,18, SEEK_SET);
01769                 Bit8u size[4];
01770                 size[0]=(Bit8u)(capture.midi.done >> 24);
01771                 size[1]=(Bit8u)(capture.midi.done >> 16);
01772                 size[2]=(Bit8u)(capture.midi.done >> 8);
01773                 size[3]=(Bit8u)(capture.midi.done >> 0);
01774                 fwrite(&size,1,4,capture.midi.handle);
01775                 fclose(capture.midi.handle);
01776                 capture.midi.handle=0;
01777                 CaptureState &= ~((unsigned int)CAPTURE_MIDI);
01778                 return;
01779         } 
01780         CaptureState ^= CAPTURE_MIDI;
01781         if (CaptureState & CAPTURE_MIDI) {
01782                 LOG_MSG("Preparing for raw midi capture, will start with first data.");
01783                 capture.midi.used=0;
01784                 capture.midi.done=0;
01785                 capture.midi.handle=0;
01786         } else {
01787                 LOG_MSG("Stopped capturing raw midi before any data arrived.");
01788         }
01789 
01790         mainMenu.get_item("mapper_caprawmidi").check(!!(CaptureState & CAPTURE_MIDI)).refresh_item(mainMenu);
01791 }
01792 
01793 void CAPTURE_Destroy(Section *sec) {
01794     (void)sec;//UNUSED
01795         // if capture is active, fake mapper event to "toggle" it off for each capture case.
01796 #if (C_SSHOT)
01797         if (capture.video.writer != NULL) CAPTURE_VideoEvent(true);
01798 #endif
01799     if (capture.multitrack_wave.writer) CAPTURE_MTWaveEvent(true);
01800         if (capture.wave.writer) CAPTURE_WaveEvent(true);
01801         if (capture.midi.handle) CAPTURE_MidiEvent(true);
01802 }
01803 
01804 void CAPTURE_Init() {
01805         DOSBoxMenu::item *item;
01806 
01807         LOG(LOG_MISC,LOG_DEBUG)("Initializing screenshot and A/V capture system");
01808 
01809         Section_prop *section = static_cast<Section_prop *>(control->GetSection("dosbox"));
01810         assert(section != NULL);
01811 
01812         // grab and store capture path
01813         Prop_path *proppath = section->Get_path("captures");
01814         assert(proppath != NULL);
01815         capturedir = proppath->realpath;
01816 
01817     skip_encoding_unchanged_frames = section->Get_bool("skip encoding unchanged frames");
01818 
01819     std::string ffmpeg_pixfmt = section->Get_string("capture chroma format");
01820 
01821 #if (C_AVCODEC)
01822     if (ffmpeg_pixfmt == "4:4:4")
01823         ffmpeg_yuv_format_choice = 4;
01824     else if (ffmpeg_pixfmt == "4:2:2")
01825         ffmpeg_yuv_format_choice = 2;
01826     else if (ffmpeg_pixfmt == "4:2:0")
01827         ffmpeg_yuv_format_choice = 0;
01828     else
01829         ffmpeg_yuv_format_choice = -1;
01830 #endif
01831 
01832         std::string capfmt = section->Get_string("capture format");
01833         if (capfmt == "mpegts-h264") {
01834 #if (C_AVCODEC)
01835                 LOG_MSG("Capture format is MPEGTS H.264+AAC");
01836                 native_zmbv = false;
01837                 export_ffmpeg = true;
01838 #else
01839                 LOG_MSG("MPEGTS H.264+AAC not compiled in to this DOSBox-X binary. Using AVI+ZMBV");
01840                 native_zmbv = true;
01841                 export_ffmpeg = false;
01842 #endif
01843         }
01844         else if (capfmt == "avi-zmbv" || capfmt == "default") {
01845                 LOG_MSG("USING AVI+ZMBV");
01846                 native_zmbv = true;
01847                 export_ffmpeg = false;
01848         }
01849         else {
01850                 LOG_MSG("Unknown capture format, using AVI+ZMBV");
01851                 native_zmbv = true;
01852                 export_ffmpeg = false;
01853         }
01854 
01855         CaptureState = 0; // make sure capture is off
01856 
01857 #if !defined(C_EMSCRIPTEN)
01858         // mapper shortcuts for capture
01859         MAPPER_AddHandler(CAPTURE_WaveEvent,MK_w,MMOD3|MMODHOST,"recwave","Rec Wave", &item);
01860         item->set_text("Record audio to WAV");
01861 
01862         MAPPER_AddHandler(CAPTURE_MTWaveEvent,MK_nothing,0,"recmtwave","Rec MTWav", &item);
01863         item->set_text("Record audio to multi-track AVI");
01864 
01865         MAPPER_AddHandler(CAPTURE_MidiEvent,MK_nothing,0,"caprawmidi","Cap MIDI", &item);
01866         item->set_text("Record MIDI output");
01867 
01868 #if (C_SSHOT)
01869         MAPPER_AddHandler(CAPTURE_ScreenShotEvent,MK_s,MMOD3|MMODHOST,"scrshot","Screenshot", &item);
01870         item->set_text("Take screenshot");
01871 
01872         MAPPER_AddHandler(CAPTURE_VideoEvent,MK_v,MMOD3|MMODHOST,"video","Video", &item);
01873         item->set_text("Record video to AVI");
01874 #endif
01875 #endif
01876 
01877         AddExitFunction(AddExitFunctionFuncPair(CAPTURE_Destroy),true);
01878 }
01879 
01880 void HARDWARE_Destroy(Section * sec) {
01881     (void)sec;//UNUSED
01882 }
01883 
01884 void HARDWARE_Init() {
01885         LOG(LOG_MISC,LOG_DEBUG)("HARDWARE_Init: initializing");
01886 
01887         /* TODO: Hardware init. We moved capture init to it's own function. */
01888         AddExitFunction(AddExitFunctionFuncPair(HARDWARE_Destroy),true);
01889 }
01890 
01891 #if !defined(C_EMSCRIPTEN)
01892 void update_capture_fmt_menu(void) {
01893 # if (C_SSHOT)
01894     mainMenu.get_item("capture_fmt_avi_zmbv").check(native_zmbv).refresh_item(mainMenu);
01895 #  if (C_AVCODEC)
01896     mainMenu.get_item("capture_fmt_mpegts_h264").check(export_ffmpeg).refresh_item(mainMenu);
01897 #  endif
01898 # endif
01899 }
01900 #endif
01901 
01902 bool capture_fmt_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) {
01903     (void)menu;
01904 
01905     const char *ts = menuitem->get_name().c_str();
01906     Bitu old_CaptureState = CaptureState;
01907     bool new_native_zmbv = native_zmbv;
01908     bool new_export_ffmpeg = export_ffmpeg;
01909 
01910     if (!strncmp(ts,"capture_fmt_",12))
01911         ts += 12;
01912 
01913 #if (C_AVCODEC)
01914     if (!strcmp(ts,"mpegts_h264")) {
01915         new_native_zmbv = false;
01916         new_export_ffmpeg = true;
01917     }
01918     else
01919 #endif
01920     {
01921         new_native_zmbv = true;
01922         new_export_ffmpeg = false;
01923     }
01924 
01925     if (native_zmbv != new_native_zmbv || export_ffmpeg != new_export_ffmpeg) {
01926         void CAPTURE_StopCapture(void);
01927         CAPTURE_StopCapture();
01928 
01929         native_zmbv = new_native_zmbv;
01930         export_ffmpeg = new_export_ffmpeg;
01931     }
01932 
01933     if (old_CaptureState & CAPTURE_VIDEO) {
01934         void CAPTURE_StartCapture(void);
01935         CAPTURE_StartCapture();
01936     }
01937 
01938 #if !defined(C_EMSCRIPTEN)
01939     update_capture_fmt_menu();
01940 #endif
01941     return true;
01942 }
01943