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