~ubuntu-branches/ubuntu/lucid/fceux/lucid

« back to all changes in this revision

Viewing changes to fceu/src/drivers/videolog/nesvideos-piece.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Fabrice Coutadeur
  • Date: 2009-12-14 08:05:17 UTC
  • Revision ID: james.westby@ubuntu.com-20091214080517-abi5tj8avthfan7c
Tags: upstream-2.1.2+repack
ImportĀ upstreamĀ versionĀ 2.1.2+repack

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#define THREAD_SAFETY
 
2
 
 
3
#include <cmath>
 
4
#include <string>
 
5
#include <vector>
 
6
#include <deque>
 
7
#include <list>
 
8
#include <map>
 
9
 
 
10
#include <unistd.h>   // mknod, unlink, write
 
11
#include <stdio.h>
 
12
#include <sys/stat.h> // S_IFIFO
 
13
#include <fcntl.h>    // fcntl
 
14
#include <sys/poll.h> // poll
 
15
#include <stdlib.h>   // setenv
 
16
#include <string.h>   // strrchr
 
17
#include <sys/file.h> // flock
 
18
#include <errno.h>
 
19
#include <glob.h>
 
20
 
 
21
#ifdef HAVE_GD
 
22
#include <gd.h>
 
23
#endif
 
24
 
 
25
#ifdef HAVE_X264 // don't worry, you really don't need it
 
26
extern "C" {
 
27
#include <x264.h>
 
28
}
 
29
#endif
 
30
 
 
31
/* Note: This module assumes everyone uses BGR16 as display depth */
 
32
 
 
33
//#define LOGO_LENGTH_HEADER  (1.2)
 
34
//#define LOGO_LENGTH_OVERLAP (10.0-LOGO_LENGTH_HEADER)
 
35
//#define LOGO_LENGTH_HEADER  (1.1)
 
36
//#define LOGO_LENGTH_OVERLAP (3.95-LOGO_LENGTH_HEADER)
 
37
//#define LOGO_LENGTH_OVERLAP (3-LOGO_LENGTH_HEADER)
 
38
//#define LOGO_LENGTH_HEADER  (1.5)
 
39
#define LOGO_LENGTH_OVERLAP (0)
 
40
#define LOGO_LENGTH_HEADER (0)
 
41
 
 
42
static std::string VIDEO_CMD = "";
 
43
/*
 
44
-rawvideo on:fps=60:format=0x42475220:w=256:h=224:size=$[1024*224]
 
45
-audiofile "+AUDIO_FN+"
 
46
*/
 
47
static std::string AUDIO_FN = "s.log";
 
48
 
 
49
static bool Terminate=false;
 
50
static unsigned videonumber = 0;
 
51
 
 
52
#ifdef THREAD_SAFETY
 
53
# include <pthread.h>
 
54
static pthread_mutex_t APIlock = PTHREAD_MUTEX_INITIALIZER;
 
55
struct ScopedLock
 
56
{ ScopedLock() { 
 
57
                 pthread_mutex_lock(&APIlock);
 
58
                 //fprintf(stderr, "audio start\n"); fflush(stderr);
 
59
               }
 
60
  ~ScopedLock() {
 
61
                 //fprintf(stderr, "audio end\n"); fflush(stderr);
 
62
                 pthread_mutex_unlock(&APIlock); }
 
63
};
 
64
#endif
 
65
 
 
66
static unsigned NonblockWrite(FILE* fp, const unsigned char*buf, unsigned length)
 
67
{
 
68
  Retry:
 
69
    int result = write(fileno(fp), buf, length);
 
70
    if(result == -1 && errno==EAGAIN)
 
71
    {
 
72
        return 0;
 
73
    }
 
74
    if(result == -1 && errno==EINTR) goto Retry;
 
75
    if(result == -1)
 
76
    {
 
77
        perror("write");
 
78
        Terminate=true;
 
79
        return 0;
 
80
    }
 
81
    return result;
 
82
}
 
83
static int WaitUntilOneIsWritable(FILE*f1, FILE*f2)
 
84
{
 
85
    struct pollfd po[2] = { {fileno(f1),POLLOUT,0}, {fileno(f2),POLLOUT,0} };
 
86
    poll(po, 2, -1);
 
87
    return ((po[0].revents & POLLOUT) ? 1 : 0)
 
88
         | ((po[1].revents & POLLOUT) ? 2 : 0);
 
89
}
 
90
 
 
91
#define BGR32 0x42475220  // BGR32 fourcc
 
92
#define BGR24 0x42475218  // BGR24 fourcc
 
93
#define BGR16 0x42475210  // BGR16 fourcc
 
94
#define BGR15 0x4247520F  // BGR15 fourcc
 
95
#define I420  0x30323449  // I420 fourcc
 
96
#define YUY2  0x32595559  // YUY2 fourcc
 
97
 
 
98
static unsigned USE_FOURCC = BGR16;
 
99
static unsigned INPUT_BPP  = 16;
 
100
 
 
101
#define u32(n) (n)&255,((n)>>8)&255,((n)>>16)&255,((n)>>24)&255
 
102
#define u16(n) (n)&255,((n)>>8)&255
 
103
#define s4(s) s[0],s[1],s[2],s[3]
 
104
 
 
105
static const unsigned FPS_SCALE = 0x1000000;
 
106
 
 
107
static struct Construct
 
108
{
 
109
    Construct()
 
110
    {
 
111
        char Buf[4096];
 
112
        getcwd(Buf,sizeof(Buf));
 
113
        Buf[sizeof(Buf)-1]=0;
 
114
        AUDIO_FN = Buf + std::string("/") + AUDIO_FN;
 
115
    }
 
116
} Construct;
 
117
 
 
118
class AVI
 
119
{
 
120
public:
 
121
    AVI()          { }
 
122
    virtual ~AVI() { }
 
123
 
 
124
    virtual void Audio
 
125
        (unsigned r,unsigned b,unsigned c,
 
126
         const unsigned char*d, unsigned nsamples) = 0;
 
127
 
 
128
    virtual void Video
 
129
        (unsigned w,unsigned h,unsigned f, const unsigned char*d) = 0;
 
130
    
 
131
    virtual void SaveState(const std::string&) { }
 
132
    virtual void LoadState(const std::string&) { }
 
133
};
 
134
 
 
135
class NormalAVI: public AVI
 
136
{
 
137
    FILE* vidfp;
 
138
    FILE* audfp;
 
139
    
 
140
    bool KnowVideo;
 
141
    unsigned vid_width;
 
142
    unsigned vid_height;
 
143
    unsigned vid_fps_scaled;
 
144
    std::list<std::vector<unsigned char> > VideoBuffer;
 
145
    unsigned VidBufSize;
 
146
    
 
147
    bool KnowAudio;
 
148
    unsigned aud_rate;
 
149
    unsigned aud_chans;
 
150
    unsigned aud_bits;
 
151
    std::list<std::vector<unsigned char> > AudioBuffer;
 
152
    unsigned AudBufSize;
 
153
    
 
154
public:
 
155
    NormalAVI() :
 
156
        vidfp(NULL),
 
157
        audfp(NULL),
 
158
        KnowVideo(false), VidBufSize(0),
 
159
        KnowAudio(false), AudBufSize(0)
 
160
    {
 
161
    }
 
162
    virtual ~NormalAVI()
 
163
    {
 
164
        while(VidBufSize && AudBufSize)
 
165
        {
 
166
            CheckFlushing();
 
167
        }
 
168
        if(audfp) fclose(audfp);
 
169
        if(vidfp) pclose(vidfp);
 
170
        unlink(AUDIO_FN.c_str());
 
171
    }
 
172
    
 
173
    virtual void Audio
 
174
        (unsigned r,unsigned b,unsigned c,
 
175
         const unsigned char*d, unsigned nsamples)
 
176
    {
 
177
        if(Terminate) return;
 
178
        if(!KnowAudio)
 
179
        {
 
180
            aud_rate = r;
 
181
            aud_chans = c;
 
182
            aud_bits = b;
 
183
            KnowAudio = true;
 
184
        }
 
185
        CheckFlushing();
 
186
        
 
187
        unsigned bytes = nsamples * aud_chans * (aud_bits / 8);
 
188
        
 
189
        unsigned wrote = 0;
 
190
        if(KnowVideo && AudioBuffer.empty())
 
191
        {
 
192
            //fprintf(stderr, "Writing %u of %s from %p to %p\t", bytes, "aud", (void*)d, (void*)audfp);
 
193
            wrote = NonblockWrite(audfp, d, bytes);
 
194
            //fprintf(stderr, "Wrote %u\n", wrote);
 
195
        }
 
196
        if(wrote < bytes)
 
197
        {
 
198
            unsigned remain = bytes-wrote;
 
199
            //fprintf(stderr, "Buffering %u of %s (%p..%p)\n", remain, "aud", d+wrote, d+bytes);
 
200
            AudioBuffer.push_back(std::vector<unsigned char>(d+wrote, d+bytes));
 
201
            AudBufSize += remain;
 
202
        }
 
203
        CheckFlushing();
 
204
    }
 
205
 
 
206
    virtual void Video
 
207
        (unsigned w,unsigned h,unsigned f, const unsigned char*d)
 
208
    {
 
209
        if(Terminate) return;
 
210
        if(!KnowVideo)
 
211
        {
 
212
            vid_width      = w;
 
213
            vid_height     = h;
 
214
            vid_fps_scaled = f;
 
215
            KnowVideo = true;
 
216
        }
 
217
        CheckFlushing();
 
218
        
 
219
        unsigned bpp   = INPUT_BPP; if(bpp == 15 || bpp == 17) bpp = 16;
 
220
        unsigned bytes = vid_width * vid_height * bpp / 8;
 
221
        
 
222
        //std::vector<unsigned char> tmp(bytes, 'k');
 
223
        //d = &tmp[0];
 
224
        
 
225
        unsigned wrote = 0;
 
226
        if(KnowAudio && VideoBuffer.empty())
 
227
        {
 
228
            CheckBegin();
 
229
            //fprintf(stderr, "Writing %u of %s from %p to %p\t", bytes, "vid", (void*)d, (void*)vidfp);
 
230
            wrote = NonblockWrite(vidfp, d, bytes);
 
231
            //fprintf(stderr, "Wrote %u\n", wrote);
 
232
        }
 
233
        
 
234
        if(wrote < bytes)
 
235
        {
 
236
            unsigned remain = bytes-wrote;
 
237
            //fprintf(stderr, "Buffering %u of %s (%p..%p)\n", remain, "vid", d+wrote, d+bytes);
 
238
 
 
239
            VideoBuffer.push_back(std::vector<unsigned char>(d+wrote, d+bytes));
 
240
            VidBufSize += remain;
 
241
        }
 
242
        CheckFlushing();
 
243
    }
 
244
 
 
245
private:
 
246
    /* fp is passed as a reference because it may be NULL
 
247
     * prior to calling, and this function changes it. */
 
248
    template<typename BufType>
 
249
    void FlushBufferSome(BufType& List, unsigned& Size, FILE*& fp, const char* what)
 
250
    {
 
251
        what=what;
 
252
        
 
253
    Retry:
 
254
        if(List.empty() || Terminate) return;
 
255
        
 
256
        typename BufType::iterator i = List.begin();
 
257
        std::vector<unsigned char>& buf = *i;
 
258
        
 
259
        if(buf.empty())
 
260
        {
 
261
            List.erase(i);
 
262
            goto Retry;
 
263
        }
 
264
        
 
265
        unsigned bytes = buf.size();
 
266
        
 
267
        CheckBegin();
 
268
        //fprintf(stderr, "Writing %u of %s from %p to %p\t", bytes, what, (void*)&buf[0], (void*)fp);
 
269
        
 
270
        unsigned ate = NonblockWrite(fp, &buf[0], bytes);
 
271
 
 
272
        //fprintf(stderr, "Wrote %u\n", ate);
 
273
        
 
274
        buf.erase(buf.begin(), buf.begin()+ate);
 
275
        
 
276
        Size -= ate;
 
277
        
 
278
        if(buf.empty())
 
279
        {
 
280
            List.erase(i);
 
281
        }
 
282
    }
 
283
 
 
284
    void CheckFlushing()
 
285
    {
 
286
        //AudioBuffer.clear();
 
287
        //VideoBuffer.clear();
 
288
        
 
289
        if(KnowAudio && KnowVideo && !Terminate)
 
290
        {
 
291
            if(!AudioBuffer.empty() && !VideoBuffer.empty())
 
292
            {
 
293
                do {
 
294
                    /* vidfp = &1, audfp = &2 */
 
295
                    int attempt = WaitUntilOneIsWritable(vidfp, audfp);
 
296
                    
 
297
                    if(attempt <= 0) break; /* Some kind of error can cause this */
 
298
 
 
299
                    // Flush Video
 
300
                    if(attempt&1) FlushBufferSome(VideoBuffer, VidBufSize, vidfp, "vid");
 
301
                    
 
302
                    // Flush Audio
 
303
                    if(attempt&2) FlushBufferSome(AudioBuffer, AudBufSize, audfp, "aud");
 
304
                } while (!AudioBuffer.empty() && !VideoBuffer.empty());
 
305
            }
 
306
            else
 
307
            {
 
308
                FlushBufferSome(VideoBuffer, VidBufSize, vidfp, "vid");
 
309
                FlushBufferSome(AudioBuffer, AudBufSize, audfp, "aud");
 
310
            }
 
311
            /*
 
312
            fprintf(stderr, "Buffer Sizes: Audio %u(%u) video %u(%u)\n",
 
313
                (unsigned)AudioBuffer.size(), AudBufSize,
 
314
                (unsigned)VideoBuffer.size(), VidBufSize);
 
315
            */
 
316
        }
 
317
    }
 
318
    std::string GetMEncoderRawvideoParam() const
 
319
    {
 
320
        char Buf[512];
 
321
        unsigned bpp   = INPUT_BPP; if(bpp == 15 || bpp == 17) bpp = 16;
 
322
        sprintf(Buf, "fps=%g:format=0x%04X:w=%u:h=%u:size=%u",
 
323
            vid_fps_scaled / (double)FPS_SCALE,
 
324
            USE_FOURCC,
 
325
            vid_width,
 
326
            vid_height,
 
327
            vid_width*vid_height * bpp/8);
 
328
        return Buf;
 
329
    }
 
330
    std::string GetMEncoderRawaudioParam() const
 
331
    {
 
332
        char Buf[512];
 
333
        sprintf(Buf, "channels=%u:rate=%u:samplesize=%u:bitrate=%u",
 
334
            aud_chans,
 
335
            aud_rate,
 
336
            aud_bits/8,
 
337
            aud_rate*aud_chans*(aud_bits/8) );
 
338
        return Buf;
 
339
    }
 
340
    std::string GetMEncoderCommand() const
 
341
    {
 
342
        std::string mandatory = "-audiofile " + AUDIO_FN
 
343
                              + " -audio-demuxer rawaudio"
 
344
                              + " -demuxer rawvideo"
 
345
                              + " -rawvideo " + GetMEncoderRawvideoParam()
 
346
                              + " -rawaudio " + GetMEncoderRawaudioParam()
 
347
                              ;
 
348
        std::string cmd = VIDEO_CMD;
 
349
 
 
350
        std::string::size_type p = cmd.find("NESV""SETTINGS");
 
351
        if(p != cmd.npos)
 
352
            cmd = cmd.replace(p, 4+8, mandatory);
 
353
        else
 
354
            fprintf(stderr, "Warning: NESVSETTINGS not found in videocmd\n");
 
355
        
 
356
        char videonumstr[64];
 
357
        sprintf(videonumstr, "%u", videonumber);
 
358
        
 
359
        for(;;)
 
360
        {
 
361
            p = cmd.find("VIDEO""NUMBER");
 
362
            if(p == cmd.npos) break;
 
363
            cmd = cmd.replace(p, 5+6, videonumstr);
 
364
        }
 
365
        
 
366
        fprintf(stderr, "Launch: %s\n", cmd.c_str()); fflush(stderr);
 
367
        
 
368
        return cmd;
 
369
    }
 
370
 
 
371
    void CheckBegin()
 
372
    {
 
373
        if(!audfp)
 
374
        {
 
375
            unlink(AUDIO_FN.c_str());
 
376
            mknod(AUDIO_FN.c_str(), S_IFIFO|0666, 0);
 
377
        }
 
378
        
 
379
        if(!vidfp)
 
380
        {
 
381
            /* Note: popen does not accept b/t in mode param */
 
382
            setenv("LD_PRELOAD", "", 1);
 
383
            vidfp = popen(GetMEncoderCommand().c_str(), "w");
 
384
            if(!vidfp)
 
385
            {
 
386
                perror("Launch failed");
 
387
            }
 
388
            else
 
389
            {
 
390
                fcntl(fileno(vidfp), F_SETFL, O_WRONLY | O_NONBLOCK);
 
391
            }
 
392
        }
 
393
        
 
394
        if(!audfp)
 
395
        {
 
396
        Retry:
 
397
            audfp = fopen(AUDIO_FN.c_str(), "wb");
 
398
            
 
399
            if(!audfp)
 
400
            {
 
401
                perror(AUDIO_FN.c_str());
 
402
                if(errno == ESTALE) goto Retry;
 
403
            }
 
404
            else
 
405
            {
 
406
                fcntl(fileno(audfp), F_SETFL, O_WRONLY | O_NONBLOCK);
 
407
            }
 
408
        }
 
409
    }
 
410
};
 
411
 
 
412
class RerecordingAVI: public AVI
 
413
{
 
414
    std::map<std::string, std::pair<off_t, off_t> > FrameStates;
 
415
    size_t aud_framesize;
 
416
    size_t vid_framesize;
 
417
    
 
418
    FILE* vidfp;
 
419
    FILE* audfp;
 
420
    FILE* eventfp;
 
421
    FILE* statefp;
 
422
    /*
 
423
    std::string vidfn;
 
424
    std::string audfn;
 
425
    std::string eventfn;
 
426
    std::string statefn;
 
427
    */
 
428
    
 
429
#ifdef HAVE_X264
 
430
    x264_t*        x264;
 
431
    x264_param_t   param;
 
432
    bool           forcekey;
 
433
#endif
 
434
    
 
435
    class LockF
 
436
    {
 
437
    public:
 
438
        LockF(FILE* f) : fp(f) { flock(fileno(fp), LOCK_EX); }
 
439
        ~LockF()               { flock(fileno(fp), LOCK_UN); }
 
440
    private:
 
441
        LockF(const LockF&);
 
442
        LockF& operator=(const LockF&);
 
443
        FILE* fp;
 
444
    };
 
445
    
 
446
public:
 
447
    RerecordingAVI(long FrameNumber)
 
448
        : aud_framesize(0),
 
449
          vid_framesize(0)
 
450
#ifdef HAVE_X264
 
451
          ,x264(0),
 
452
          forcekey(true)
 
453
#endif
 
454
    {
 
455
        SetFn();
 
456
    }
 
457
    virtual ~RerecordingAVI()
 
458
    {
 
459
        if(eventfp)
 
460
        {
 
461
            off_t vidpos = ftello(vidfp);
 
462
            off_t audpos = ftello(audfp);
 
463
            fprintf(eventfp,
 
464
                "%llX %llX End\n",
 
465
                (long long)vidpos, (long long)audpos);
 
466
        }
 
467
        if(vidfp) fclose(vidfp);
 
468
        if(audfp) fclose(audfp);
 
469
        if(eventfp) fclose(eventfp);
 
470
        if(statefp) fclose(statefp);
 
471
#ifdef HAVE_X264
 
472
        if(x264) x264_encoder_close(x264);
 
473
#endif
 
474
    }
 
475
 
 
476
    virtual void Audio
 
477
        (unsigned aud_rate,unsigned aud_bits,unsigned aud_chans,
 
478
         const unsigned char*data, unsigned nsamples)
 
479
    {
 
480
        size_t bytes = nsamples     * aud_chans * (aud_bits / 8);
 
481
        size_t framesize = aud_rate * aud_chans * (aud_bits / 8);
 
482
        
 
483
        if(framesize != aud_framesize)
 
484
        {
 
485
            aud_framesize = framesize;
 
486
            LockF el(eventfp);
 
487
            fprintf(eventfp, "AudFrameSize %lu\n", (unsigned long)aud_framesize);
 
488
            fflush(eventfp);
 
489
        }
 
490
        
 
491
        LockF al(audfp);
 
492
        fwrite(data, 1, bytes, audfp);
 
493
    }
 
494
 
 
495
    virtual void Video
 
496
        (unsigned vid_width,unsigned vid_height,
 
497
         unsigned vid_fps_scaled, const unsigned char*data)
 
498
    {
 
499
        unsigned bpp   = INPUT_BPP; if(bpp == 15 || bpp == 17) bpp = 16;
 
500
        size_t bytes = vid_width * vid_height * bpp / 8;
 
501
        size_t framesize = bytes;
 
502
 
 
503
        if(framesize != vid_framesize)
 
504
        {
 
505
            vid_framesize = framesize;
 
506
            LockF el(eventfp);
 
507
            fprintf(eventfp, "VidFrameSize %lu\n", (unsigned long)vid_framesize);
 
508
            fflush(eventfp);
 
509
        }
 
510
 
 
511
        LockF vl(vidfp);
 
512
        
 
513
#ifdef HAVE_X264
 
514
        if(bpp == 12) /* For I420, we use a local X264 encoder */
 
515
        {
 
516
            if(!x264)
 
517
            {
 
518
                x264_param_default(&param);
 
519
                x264_param_parse(&param, "psnr", "no");
 
520
                x264_param_parse(&param, "ssim", "no");
 
521
                param.i_width  = vid_width;
 
522
                param.i_height = vid_height;
 
523
                param.i_csp    = X264_CSP_I420;
 
524
                //param.i_scenecut_threshold = -1;
 
525
                //param.b_bframe_adaptive     = 0;
 
526
                //param.rc.i_rc_method      = X264_RC_CRF;
 
527
                //param.rc.i_qp_constant    = 0;
 
528
                x264_param_parse(&param, "me",       "dia");
 
529
                x264_param_parse(&param, "crf",      "6");
 
530
                x264_param_parse(&param, "frameref", "8");
 
531
                param.i_frame_reference = 1;
 
532
                param.analyse.i_subpel_refine = 1;
 
533
                param.analyse.i_me_method = X264_ME_DIA;
 
534
                /*
 
535
                param.analyse.inter = 0;
 
536
                param.analyse.b_transform_8x8 = 0;
 
537
                param.analyse.b_weighted_bipred = 0;
 
538
                param.analyse.i_trellis = 0;
 
539
                */
 
540
                //param.b_repeat_headers = 1; // guess this might be needed
 
541
                
 
542
                param.i_fps_num = vid_fps_scaled;
 
543
                param.i_fps_den = 1 << 24;
 
544
                
 
545
                x264 = x264_encoder_open(&param);
 
546
                if(!x264)
 
547
                {
 
548
                    fprintf(stderr, "x264_encoder_open failed.\n");
 
549
                    goto raw_fallback;
 
550
                }
 
551
            }
 
552
            
 
553
            const size_t npixels = vid_width * vid_height;
 
554
            x264_picture_t pic;
 
555
            pic.i_type = forcekey ? X264_TYPE_IDR : X264_TYPE_AUTO;
 
556
            pic.i_pts  = 0;
 
557
            pic.i_qpplus1 = 0;
 
558
            pic.img.i_csp = X264_CSP_I420;
 
559
            pic.img.i_plane = 3;
 
560
            pic.img.i_stride[0] = vid_width;
 
561
            pic.img.i_stride[1] = vid_width / 2;
 
562
            pic.img.i_stride[2] = vid_width / 2;
 
563
            pic.img.plane[0] = const_cast<uint8_t*>(data) + npixels*0/4;
 
564
            pic.img.plane[1] = const_cast<uint8_t*>(data) + npixels*4/4;
 
565
            pic.img.plane[2] = const_cast<uint8_t*>(data) + npixels*5/4;
 
566
            
 
567
            x264_nal_t*    nal; int i_nal;
 
568
            x264_picture_t pic_out;
 
569
            if(x264_encoder_encode(x264, &nal, &i_nal, &pic, &pic_out) < 0)
 
570
            {
 
571
                fprintf(stderr, "x264_encoder_encode failed\n");
 
572
                goto raw_fallback;
 
573
            }
 
574
            int i_size = 0;
 
575
            for(int i=0; i<i_nal; ++i) i_size += nal[i].i_payload * 2 + 4;
 
576
            std::vector<unsigned char> muxbuf(i_size);
 
577
            i_size = 0;
 
578
            for(int i=0; i<i_nal; ++i)
 
579
            {
 
580
                int room_required = nal[i].i_payload * 3/2 + 4;
 
581
                if(muxbuf.size() < i_size + room_required)
 
582
                    muxbuf.resize(i_size + room_required);
 
583
                
 
584
                int i_data = muxbuf.size() - i_size;
 
585
                i_size += x264_nal_encode(&muxbuf[i_size], &i_data, 1, &nal[i]);
 
586
            }
 
587
            if(i_size > 0)
 
588
                fwrite(&muxbuf[0], 1, i_size, vidfp);
 
589
        }
 
590
        else
 
591
#endif
 
592
        {
 
593
        raw_fallback:
 
594
            fwrite(data, 1, bytes, vidfp);
 
595
        }
 
596
 
 
597
        if(eventfp)
 
598
        {
 
599
            LockF el(eventfp);
 
600
            off_t vidpos = ftello(vidfp);
 
601
            off_t audpos = ftello(audfp);
 
602
            fprintf(eventfp,
 
603
                "%llX %llX Mark\n",
 
604
                (long long)vidpos, (long long)audpos);
 
605
            fflush(eventfp);
 
606
        }
 
607
    }
 
608
    
 
609
#ifdef HAVE_X264
 
610
    virtual void SaveState(const std::string& slot)
 
611
    {
 
612
        LockF el(eventfp);
 
613
        
 
614
        off_t vidpos = ftello(vidfp);
 
615
        off_t audpos = ftello(audfp);
 
616
    
 
617
        fprintf(eventfp,
 
618
            "%llX %llX Save %s\n",
 
619
             (long long)vidpos, (long long)audpos, slot.c_str());
 
620
        fflush(eventfp);
 
621
        
 
622
        FrameStates[slot] = std::make_pair(vidpos, audpos);
 
623
        WriteStates();
 
624
        
 
625
        forcekey = true;
 
626
    }
 
627
    
 
628
    virtual void LoadState(const std::string& slot)
 
629
    {
 
630
        LockF el(eventfp);
 
631
 
 
632
        const std::pair<off_t, off_t>& old = FrameStates[slot];
 
633
        off_t vidpos = ftello(vidfp);
 
634
        off_t audpos = ftello(audfp);
 
635
        fprintf(eventfp,
 
636
            "%llX %llX Load %llX %llX %s\n",
 
637
            (long long)vidpos, (long long)audpos,
 
638
            (long long)old.first,
 
639
            (long long)old.second,
 
640
            slot.c_str());
 
641
        fflush(eventfp);
 
642
 
 
643
        forcekey = true;
 
644
    }
 
645
#endif
 
646
private:
 
647
    void SetFn()
 
648
    {
 
649
        std::string vidfn = VIDEO_CMD + ".vid";
 
650
        std::string audfn = VIDEO_CMD + ".aud";
 
651
        std::string eventfn = VIDEO_CMD + ".log";
 
652
        std::string statefn = VIDEO_CMD + ".state";
 
653
        vidfp = fopen(vidfn.c_str(), "ab+");
 
654
        audfp = fopen(audfn.c_str(), "ab+");
 
655
        eventfp = fopen(eventfn.c_str(), "ab+");
 
656
        statefp = fopen2(statefn.c_str(), "rb+", "wb+");
 
657
        ReadStates();
 
658
 
 
659
        if(eventfp)
 
660
        {
 
661
            off_t vidpos = ftello(vidfp);
 
662
            off_t audpos = ftello(audfp);
 
663
            fprintf(eventfp,
 
664
                "%llX %llX Begin\n",
 
665
                (long long)vidpos, (long long)audpos);
 
666
        }
 
667
    }
 
668
    static FILE* fopen2(const char* fn, const char* mode1, const char* mode2)
 
669
    {
 
670
        FILE* result = fopen(fn, mode1);
 
671
        if(!result) result = fopen(fn, mode2);
 
672
        return result;
 
673
    }
 
674
    void ReadStates()
 
675
    {
 
676
        LockF sl(statefp);
 
677
        
 
678
        char Buf[4096];
 
679
        rewind(statefp);
 
680
        FrameStates.clear();
 
681
        while(fgets(Buf, sizeof(Buf), statefp))
 
682
        {
 
683
            if(*Buf == '-') break;
 
684
            char slotname[4096];
 
685
            long long vidpos, audpos;
 
686
            strtok(Buf, "\r"); strtok(Buf, "\n");
 
687
            sscanf(Buf, "%llX %llX %4095s", &vidpos, &audpos, slotname);
 
688
            FrameStates[slotname] = std::pair<off_t,off_t> (vidpos, audpos);
 
689
        }
 
690
    }
 
691
    void WriteStates()
 
692
    {
 
693
        LockF sl(statefp);
 
694
        
 
695
        rewind(statefp);
 
696
        for(std::map<std::string, std::pair<off_t, off_t> >::const_iterator
 
697
            i = FrameStates.begin(); i != FrameStates.end(); ++i)
 
698
        {
 
699
            fprintf(statefp, "%llX %llX %s\n", 
 
700
                (long long) i->second.first,
 
701
                (long long) i->second.second,
 
702
                i->first.c_str());
 
703
        }
 
704
        fprintf(statefp, "-\n");
 
705
        fflush(statefp);
 
706
    }
 
707
};
 
708
 
 
709
 
 
710
static AVI* AVI = 0;
 
711
 
 
712
#ifdef HAVE_GD
 
713
namespace LogoInfo
 
714
{
 
715
    unsigned width;
 
716
    unsigned height;
 
717
 
 
718
    bool SentVideo = false;
 
719
    bool SentAudio = false;
 
720
    int OverlapSent = 0;
 
721
}
 
722
#endif
 
723
 
 
724
#include "quantize.h"
 
725
#include "rgbtorgb.h"
 
726
 
 
727
static bool RerecordingMode = false;
 
728
static long CurrentFrameNumber = 0;
 
729
 
 
730
extern "C"
 
731
{
 
732
    int LoggingEnabled = 0; /* 0=no, 1=yes, 2=recording! */
 
733
 
 
734
    const char* NESVideoGetVideoCmd()
 
735
    {
 
736
        return VIDEO_CMD.c_str();
 
737
    }
 
738
    void NESVideoSetVideoCmd(const char *cmd)
 
739
    {
 
740
#ifdef THREAD_SAFETY
 
741
        ScopedLock lock;
 
742
#endif
 
743
 
 
744
        VIDEO_CMD = cmd;
 
745
    }
 
746
    
 
747
    void NESVideoSetRerecordingMode(long FrameNumber)
 
748
    {
 
749
        //const int LogoFramesOverlap = (int)( (LOGO_LENGTH_OVERLAP * fps_scaled) / (1 << 24) );
 
750
        RerecordingMode = true;
 
751
        CurrentFrameNumber = FrameNumber;
 
752
#ifdef HAVE_GD
 
753
        LogoInfo::SentVideo = FrameNumber > 0;
 
754
        LogoInfo::SentAudio = FrameNumber > 0;
 
755
        LogoInfo::OverlapSent = FrameNumber;
 
756
#endif
 
757
    }
 
758
    
 
759
    static class AVI& GetAVIptr()
 
760
    {
 
761
        if(!AVI)
 
762
        {
 
763
            if(RerecordingMode)
 
764
            {
 
765
                fprintf(stderr, "Beginning rerecording project at frame %ld\n", CurrentFrameNumber);
 
766
                AVI = new RerecordingAVI(CurrentFrameNumber);
 
767
            }
 
768
            else
 
769
            {
 
770
                fprintf(stderr, "Starting new AVI (num %u)\n", videonumber);
 
771
                AVI = new NormalAVI;
 
772
            }
 
773
        }
 
774
        return *AVI;
 
775
    }
 
776
    
 
777
    void NESVideoRerecordingSave(const char* slot)
 
778
    {
 
779
        GetAVIptr().SaveState(slot);
 
780
    }
 
781
    
 
782
    void NESVideoRerecordingLoad(const char* slot)
 
783
    {
 
784
        GetAVIptr().LoadState(slot);
 
785
    }
 
786
    
 
787
    void NESVideoNextAVI()
 
788
    {
 
789
#ifdef THREAD_SAFETY
 
790
        ScopedLock lock;
 
791
#endif
 
792
 
 
793
        if(AVI)
 
794
        {
 
795
            fprintf(stderr, "Closing AVI (next will be started)\n");
 
796
            delete AVI;
 
797
            AVI = 0;
 
798
            ++videonumber;
 
799
        }
 
800
    }
 
801
 
 
802
 #ifdef HAVE_GD
 
803
    static void Overlay32With32(unsigned char* target, const unsigned char* source, int alpha)
 
804
    {
 
805
        target[0] += ((int)(source[0] - target[0])) * alpha / 255;
 
806
        target[1] += ((int)(source[1] - target[1])) * alpha / 255;
 
807
        target[2] += ((int)(source[2] - target[2])) * alpha / 255;
 
808
    }
 
809
    
 
810
    static void OverlayLogoFrom(const char* fn, std::vector<unsigned char>& data)
 
811
    {
 
812
        FILE*fp = fopen(fn, "rb");
 
813
        if(!fp) perror(fn);
 
814
        if(!fp) return; /* Silently ignore missing frames */
 
815
        
 
816
        gdImagePtr im = gdImageCreateFromPng(fp);
 
817
        if(!gdImageTrueColor(im))
 
818
        {
 
819
          fprintf(stderr, "'%s': Only true color images are supported\n", fn);
 
820
          goto CloseIm;
 
821
        }
 
822
        {/*scope begin*/
 
823
        
 
824
        unsigned new_width = gdImageSX(im);
 
825
        unsigned new_height= gdImageSY(im);
 
826
        
 
827
        if(new_width != LogoInfo::width
 
828
        || new_height != LogoInfo::height)
 
829
        {
 
830
            if(new_height < LogoInfo::height || new_height > LogoInfo::height+20)
 
831
            fprintf(stderr, "'%s': ERROR, expected %dx%d, got %dx%d\n", fn,
 
832
                LogoInfo::width, LogoInfo::height,
 
833
                new_width, new_height);
 
834
        }
 
835
 
 
836
        for(unsigned y=0; y<LogoInfo::height; ++y)
 
837
        {
 
838
            unsigned char pixbuf[4] = {0,0,0,0};
 
839
            for(unsigned x = 0; x < LogoInfo::width; ++x)
 
840
            {
 
841
                int color = gdImageTrueColorPixel(im, x,y);
 
842
                int alpha = 255-gdTrueColorGetAlpha(color)*256/128;
 
843
                pixbuf[2] = gdTrueColorGetRed(color);
 
844
                pixbuf[1] = gdTrueColorGetGreen(color);
 
845
                pixbuf[0] = gdTrueColorGetBlue(color);
 
846
                Overlay32With32(&data[(y*LogoInfo::width+x)*3], pixbuf, alpha);
 
847
            }
 
848
        }
 
849
        }/* close scope */
 
850
    CloseIm:
 
851
        gdImageDestroy(im);
 
852
        fclose(fp);
 
853
    }
 
854
    
 
855
    static const std::string GetLogoFileName(unsigned frameno)
 
856
    {
 
857
        std::string avdir = "/home/you/yourlogo/";
 
858
        
 
859
        char AvName[512];
 
860
        sprintf(AvName, "logo_%d_%d_f%03u.png",
 
861
            LogoInfo::width,
 
862
            LogoInfo::height,
 
863
            frameno);
 
864
        
 
865
        std::string want = avdir + AvName;
 
866
        int ac = access(want.c_str(), R_OK);
 
867
        if(ac != 0)
 
868
        {
 
869
            /* No correct avatar file? Check if there's an approximate match. */
 
870
            static std::map<int, std::vector<std::string> > files;
 
871
            if(files.empty()) /* Cache the list of logo files. */
 
872
            {
 
873
                static const char GlobPat[] = "logo_*_*_f*.png";
 
874
                glob_t globdata;
 
875
                globdata.gl_offs = 0;
 
876
                fprintf(stderr, "Loading list of usable logo animation files in %s...\n", avdir.c_str());
 
877
                int globres = glob( (avdir + GlobPat).c_str(), GLOB_NOSORT, NULL, &globdata);
 
878
                if(globres == 0)
 
879
                {
 
880
                    for(size_t n=0; n<globdata.gl_pathc; ++n)
 
881
                    {
 
882
                        const char* fn = globdata.gl_pathv[n];
 
883
                        const char* slash = strrchr(fn, '/');
 
884
                        if(slash) fn = slash+1;
 
885
                        
 
886
                        int gotw=0, goth=0, gotf=0;
 
887
                        sscanf(fn, "logo_%d_%d_f%d", &gotw,&goth,&gotf);
 
888
                        files[gotf].push_back(fn);
 
889
                    }
 
890
                }
 
891
                globfree(&globdata);
 
892
            }
 
893
            
 
894
            std::map<int, std::vector<std::string> >::const_iterator
 
895
                i = files.find(frameno);
 
896
            if(i != files.end())
 
897
            {
 
898
                std::string best;
 
899
                int bestdist = -1;
 
900
                
 
901
                const std::vector<std::string>& fnames = i->second;
 
902
                for(size_t b=fnames.size(), a=0; a<b; ++a)
 
903
                {
 
904
                    unsigned gotw=0, goth=0;
 
905
                    sscanf(fnames[a].c_str(), "logo_%u_%u", &gotw,&goth);
 
906
                    if(gotw < LogoInfo::width || goth < LogoInfo::height) continue;
 
907
                    
 
908
                    int dist = std::max(gotw - LogoInfo::width,
 
909
                                        goth - LogoInfo::height);
 
910
                    
 
911
                    if(bestdist == -1 || dist < bestdist)
 
912
                        { bestdist = dist; best = fnames[a]; }
 
913
                }
 
914
                
 
915
                if(bestdist >= 0) want = avdir + best;
 
916
            }
 
917
        }
 
918
        return want;
 
919
    }
 
920
    
 
921
    static const std::vector<unsigned char> NVConvert24To16Frame
 
922
        (const std::vector<unsigned char>& logodata)
 
923
    {
 
924
        std::vector<unsigned char> result(LogoInfo::width * LogoInfo::height * 2);
 
925
        Convert24To16Frame(&logodata[0], &result[0], LogoInfo::width * LogoInfo::height, LogoInfo::width);
 
926
        return result;
 
927
    }
 
928
    static const std::vector<unsigned char> NVConvert24To15Frame
 
929
        (const std::vector<unsigned char>& logodata)
 
930
    {
 
931
        std::vector<unsigned char> result(LogoInfo::width * LogoInfo::height * 2);
 
932
        Convert24To15Frame(&logodata[0], &result[0], LogoInfo::width * LogoInfo::height, LogoInfo::width);
 
933
        return result;
 
934
    }
 
935
    
 
936
    static const std::vector<unsigned char> NVConvert24To_I420Frame
 
937
        (const std::vector<unsigned char>& logodata)
 
938
    {
 
939
        std::vector<unsigned char> result(LogoInfo::width * LogoInfo::height * 3 / 2);
 
940
        Convert24To_I420Frame(&logodata[0], &result[0], LogoInfo::width * LogoInfo::height, LogoInfo::width);
 
941
        return result;
 
942
    }
 
943
    
 
944
    static const std::vector<unsigned char> NVConvert24To_YUY2Frame
 
945
        (const std::vector<unsigned char>& logodata)
 
946
    {
 
947
        std::vector<unsigned char> result(LogoInfo::width * LogoInfo::height * 3 / 2);
 
948
        Convert24To_YUY2Frame(&logodata[0], &result[0], LogoInfo::width * LogoInfo::height, LogoInfo::width);
 
949
        return result;
 
950
    }
 
951
    
 
952
    static const std::vector<unsigned char> NVConvert16To24Frame
 
953
        (const void* data, unsigned npixels)
 
954
    {
 
955
        std::vector<unsigned char> logodata(npixels*3); /* filled with black. */
 
956
        Convert16To24Frame(data, &logodata[0], npixels);
 
957
        return logodata;
 
958
    }
 
959
    
 
960
    static const std::vector<unsigned char> NVConvert15To24Frame
 
961
        (const void* data, unsigned npixels)
 
962
    {
 
963
        std::vector<unsigned char> logodata(npixels*3); /* filled with black. */
 
964
        Convert15To24Frame(data, &logodata[0], npixels);
 
965
        return logodata;
 
966
    }
 
967
    
 
968
    static const std::vector<unsigned char> NVConvert_I420To24Frame
 
969
        (const void* data, unsigned npixels)
 
970
    {
 
971
        std::vector<unsigned char> logodata(npixels*3); /* filled with black. */
 
972
        Convert_I420To24Frame(data, &logodata[0], npixels, LogoInfo::width);
 
973
        return logodata;
 
974
    }
 
975
    
 
976
    static const std::vector<unsigned char> NVConvert_YUY2To24Frame
 
977
        (const void* data, unsigned npixels)
 
978
    {
 
979
        std::vector<unsigned char> logodata(npixels*3); /* filled with black. */
 
980
        Convert_YUY2To24Frame(data, &logodata[0], npixels, LogoInfo::width);
 
981
        return logodata;
 
982
    }
 
983
    
 
984
    static void SubstituteWithBlackIfNeeded(const void*& data)
 
985
    {
 
986
        /* If the first frames of the animation consist of a
 
987
         * single color (such as gray for NES), replace them
 
988
         * with black to avoid ugly backgrounds on logo animations
 
989
         */
 
990
    
 
991
        static bool Deviate = false;
 
992
        static short* Replacement = 0;
 
993
        static unsigned wid=0, hei=0;
 
994
        if(Deviate)
 
995
        {
 
996
            if(Replacement) { delete[] Replacement; Replacement=0; }
 
997
            return;
 
998
        }
 
999
        
 
1000
        unsigned dim = LogoInfo::width * LogoInfo::height;
 
1001
        const short* p = (const short*)data;
 
1002
        for(unsigned a=0; a<dim; ++a)
 
1003
            if(p[a] != p[0])
 
1004
            {
 
1005
                Deviate = true;
 
1006
                return;
 
1007
            }
 
1008
        
 
1009
        if(Replacement && (wid != LogoInfo::width || hei != LogoInfo::height))
 
1010
        {
 
1011
            delete[] Replacement;
 
1012
            Replacement = 0;
 
1013
        }
 
1014
        
 
1015
        wid = LogoInfo::width;
 
1016
        hei = LogoInfo::height;
 
1017
        
 
1018
        if(!Replacement)
 
1019
        {
 
1020
            Replacement = new short[dim];
 
1021
            for(unsigned a=0; a<dim; ++a) Replacement[a]=0x0000;
 
1022
        }
 
1023
        data = (void*)Replacement;
 
1024
    }
 
1025
#endif
 
1026
 
 
1027
    void NESVideoLoggingVideo
 
1028
        (const void*data, unsigned width,unsigned height,
 
1029
         unsigned fps_scaled,
 
1030
         unsigned bpp
 
1031
        )
 
1032
    {
 
1033
        if(LoggingEnabled < 2) return;
 
1034
        
 
1035
        ++CurrentFrameNumber;
 
1036
        
 
1037
#ifdef THREAD_SAFETY
 
1038
        ScopedLock lock;
 
1039
#endif
 
1040
 
 
1041
        if(bpp == 32) /* Convert 32 to 24 */
 
1042
        {
 
1043
            bpp = 24;
 
1044
            
 
1045
            static std::vector<unsigned char> VideoBuf;
 
1046
            VideoBuf.resize(width*height * 3);
 
1047
            
 
1048
            Convert32To24Frame(data, &VideoBuf[0], width*height);
 
1049
            data = (void*)&VideoBuf[0];
 
1050
        }
 
1051
        
 
1052
        if(bpp) INPUT_BPP = bpp;
 
1053
        
 
1054
        switch(INPUT_BPP)
 
1055
        {
 
1056
            case 32: USE_FOURCC = BGR32; break;
 
1057
            case 24: USE_FOURCC = BGR24; break;
 
1058
            case 16: USE_FOURCC = BGR16; break;
 
1059
            case 15: USE_FOURCC = BGR15; break;
 
1060
            case 12: USE_FOURCC = I420; break;
 
1061
            case 17: USE_FOURCC = YUY2; break;
 
1062
        }
 
1063
        //USE_FOURCC = BGR24; // FIXME TEMPORARY
 
1064
        
 
1065
#ifdef HAVE_GD
 
1066
        const int LogoFramesHeader  = (int)( (LOGO_LENGTH_HEADER  * fps_scaled) / (1 << 24) );
 
1067
        const int LogoFramesOverlap = (int)( (LOGO_LENGTH_OVERLAP * fps_scaled) / (1 << 24) );
 
1068
        
 
1069
        LogoInfo::width  = width;
 
1070
        LogoInfo::height = height;
 
1071
        
 
1072
        if(INPUT_BPP == 16 || INPUT_BPP == 15)
 
1073
        {
 
1074
            SubstituteWithBlackIfNeeded(data);
 
1075
        }
 
1076
        else if(INPUT_BPP != 24 && INPUT_BPP != 12 && INPUT_BPP != 17)
 
1077
        {
 
1078
            fprintf(stderr, "NESVIDEOS_PIECE only supports 16 and 24 bpp, you gave %u bpp\n",
 
1079
                bpp);
 
1080
            return;
 
1081
        }
 
1082
 
 
1083
        if(!LogoInfo::SentVideo)
 
1084
        {
 
1085
            /* Send animation frames that do not involve source video? */
 
1086
            LogoInfo::SentVideo=true;
 
1087
 
 
1088
            if(LogoFramesHeader > 0)
 
1089
            {
 
1090
                for(int frame = 0; frame < LogoFramesHeader; ++frame)
 
1091
                {
 
1092
                    std::vector<unsigned char> logodata(width*height*3); /* filled with black. */
 
1093
                    
 
1094
                    std::string fn = GetLogoFileName(frame);
 
1095
                    /*fprintf(stderr, "wid=%d(%d), hei=%d(%d),fn=%s\n",
 
1096
                        width, LogoInfo::width,
 
1097
                        height, LogoInfo::height,
 
1098
                        fn.c_str());*/
 
1099
                    OverlayLogoFrom(fn.c_str(), logodata);
 
1100
                    
 
1101
                    //INPUT_BPP = 24; USE_FOURCC = BGR24; // FIXME TEMPORARY
 
1102
                    
 
1103
                    if(INPUT_BPP == 16)
 
1104
                    {
 
1105
                        std::vector<unsigned char> result = NVConvert24To16Frame(logodata);
 
1106
                        GetAVIptr().Video(width,height,fps_scaled, &result[0]);
 
1107
                    }
 
1108
                    else if(INPUT_BPP == 15)
 
1109
                    {
 
1110
                        std::vector<unsigned char> result = NVConvert24To15Frame(logodata);
 
1111
                        GetAVIptr().Video(width,height,fps_scaled, &result[0]);
 
1112
                    }
 
1113
                    else if(INPUT_BPP == 12)
 
1114
                    {
 
1115
                        std::vector<unsigned char> result = NVConvert24To_I420Frame(logodata);
 
1116
                        GetAVIptr().Video(width,height,fps_scaled, &result[0]);
 
1117
                    }
 
1118
                    else if(INPUT_BPP == 17)
 
1119
                    {
 
1120
                        std::vector<unsigned char> result = NVConvert24To_YUY2Frame(logodata);
 
1121
                        GetAVIptr().Video(width,height,fps_scaled, &result[0]);
 
1122
                    }
 
1123
                    else
 
1124
                    {
 
1125
                        GetAVIptr().Video(width,height,fps_scaled, &logodata[0]);
 
1126
                    }
 
1127
                }
 
1128
            }
 
1129
        }
 
1130
        
 
1131
        if(LogoInfo::OverlapSent < LogoFramesOverlap)
 
1132
        {
 
1133
            /* Send animation frames that mix source and animation? */
 
1134
 
 
1135
            std::string fn = GetLogoFileName(LogoInfo::OverlapSent + LogoFramesHeader);
 
1136
            /*
 
1137
            fprintf(stderr, "wid=%d(%d), hei=%d(%d),fn=%s\n",
 
1138
                width, LogoInfo::width,
 
1139
                height, LogoInfo::height,
 
1140
                fn.c_str());*/
 
1141
 
 
1142
            std::vector<unsigned char> logodata;
 
1143
            if(INPUT_BPP == 16)
 
1144
            {
 
1145
                logodata = NVConvert16To24Frame(data, width*height);
 
1146
            }
 
1147
            else if(INPUT_BPP == 15)
 
1148
            {
 
1149
                logodata = NVConvert15To24Frame(data, width*height);
 
1150
            }
 
1151
            else if(INPUT_BPP == 17)
 
1152
            {
 
1153
                logodata = NVConvert_YUY2To24Frame(data, width*height);
 
1154
            }
 
1155
            else if(INPUT_BPP == 12)
 
1156
            {
 
1157
                logodata = NVConvert_I420To24Frame(data, width*height);
 
1158
            }
 
1159
            else
 
1160
            {
 
1161
                logodata.resize(width*height*3); /* filled with black. */
 
1162
                memcpy(&logodata[0], data, width*height*3);
 
1163
            }
 
1164
 
 
1165
            OverlayLogoFrom(fn.c_str(), logodata);
 
1166
            
 
1167
//            INPUT_BPP = 24; USE_FOURCC = BGR24; // FIXME TEMPORARY
 
1168
 
 
1169
            if(INPUT_BPP == 16)
 
1170
            {
 
1171
                std::vector<unsigned char> result = NVConvert24To16Frame(logodata);
 
1172
                GetAVIptr().Video(width,height,fps_scaled, &result[0]);
 
1173
            }
 
1174
            else if(INPUT_BPP == 15)
 
1175
            {
 
1176
                std::vector<unsigned char> result = NVConvert24To15Frame(logodata);
 
1177
                GetAVIptr().Video(width,height,fps_scaled, &result[0]);
 
1178
            }
 
1179
            else if(INPUT_BPP == 12)
 
1180
            {
 
1181
                std::vector<unsigned char> result = NVConvert24To_I420Frame(logodata);
 
1182
                GetAVIptr().Video(width,height,fps_scaled, &result[0]);
 
1183
            }
 
1184
            else if(INPUT_BPP == 17)
 
1185
            {
 
1186
                std::vector<unsigned char> result = NVConvert24To_YUY2Frame(logodata);
 
1187
                GetAVIptr().Video(width,height,fps_scaled, &result[0]);
 
1188
            }
 
1189
            else
 
1190
            {
 
1191
                GetAVIptr().Video(width,height,fps_scaled, &logodata[0]);
 
1192
            }
 
1193
 
 
1194
            ++LogoInfo::OverlapSent;
 
1195
            return;
 
1196
        }
 
1197
#endif
 
1198
        
 
1199
        GetAVIptr().Video(width,height,fps_scaled,  (const unsigned char*) data);
 
1200
    }
 
1201
 
 
1202
    void NESVideoLoggingAudio
 
1203
        (const void*data,
 
1204
         unsigned rate, unsigned bits, unsigned chans,
 
1205
         unsigned nsamples)
 
1206
    {
 
1207
        if(LoggingEnabled < 2) return;
 
1208
        
 
1209
        ++CurrentFrameNumber;
 
1210
        
 
1211
#ifdef THREAD_SAFETY
 
1212
        ScopedLock lock;
 
1213
#endif
 
1214
#ifdef HAVE_GD
 
1215
        if(!LogoInfo::SentAudio && LOGO_LENGTH_HEADER > 0)
 
1216
        {
 
1217
            LogoInfo::SentAudio=true;
 
1218
            
 
1219
            double HdrLength = LOGO_LENGTH_HEADER; // N64 workaround
 
1220
            
 
1221
            const long n = (long)(rate * HdrLength)/*
 
1222
                - (rate * 0.11)*/;
 
1223
            
 
1224
            if(n > 0) {
 
1225
            unsigned bytes = n*chans*(bits/8);
 
1226
            unsigned char* buf = (unsigned char*)malloc(bytes);
 
1227
            if(buf)
 
1228
            {
 
1229
                memset(buf,0,bytes);
 
1230
                GetAVIptr().Audio(rate,bits,chans, buf, n);
 
1231
                free(buf);
 
1232
            } }
 
1233
        }
 
1234
#endif
 
1235
        
 
1236
        /*
 
1237
        fprintf(stderr, "Writing %u samples (%u bits, %u chans, %u rate)\n",
 
1238
            nsamples, bits, chans, rate);*/
 
1239
        
 
1240
        /*
 
1241
        static FILE*fp = fopen("audiodump.wav", "wb");
 
1242
        fwrite(data, 1, nsamples*(bits/8)*chans, fp);
 
1243
        fflush(fp);*/
 
1244
        
 
1245
        GetAVIptr().Audio(rate,bits,chans, (const unsigned char*) data, nsamples);
 
1246
    }
 
1247
} /* extern "C" */