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