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