~ubuntu-branches/ubuntu/hardy/avidemux/hardy

« back to all changes in this revision

Viewing changes to avidemux/mpeg2enc/readpic.cc

  • Committer: Bazaar Package Importer
  • Author(s): Matvey Kozhev
  • Date: 2007-12-18 13:53:04 UTC
  • mfrom: (1.1.7 upstream)
  • Revision ID: james.westby@ubuntu.com-20071218135304-cdqec2lg2bglyz15
Tags: 1:2.4~preview3-0.0ubuntu1
* Upload to Ubuntu. (LP: #163287, LP: #126572)
* debian/changelog: re-added Ubuntu releases.
* debian/control:
  - Require debhelper >= 5.0.51 (for dh_icons) and imagemagick.
  - Build-depend on libsdl1.2-dev instead of libsdl-dev.
  - Build against newer libx264-dev. (LP: #138854)
  - Removed libamrnb-dev, not in Ubuntu yet.
* debian/rules:
  - Install all icon sizes, using convert (upstream installs none).
  - Added missing calls to dh_installmenu, dh_installman, dh_icons and
    dh_desktop.
* debian/menu, debian/avidemux-qt.menu:
  - Corrected package and executable names.
* debian/avidemux-common.install: Install icons.
* debian/avidemux.common.manpages: Install man/avidemux.1.
* debian/links, debian/avidemux-cli.links, debian/avidemux-gtk.links:
  - Link manpages to avidemux.1.gz.
* debian/install, debian/avidemux-qt.install, debian/avidemux-gtk.desktop,
  debian/avidemux-qt.desktop: Install desktop files.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* readpic.c, read source pictures                                          */
2
 
 
3
 
/* Copyright (C) 1996, MPEG Software Simulation Group. All Rights Reserved. */
4
 
 
5
 
/*
6
 
 * Disclaimer of Warranty
7
 
 *
8
 
 * These software programs are available to the user without any license fee or
9
 
 * royalty on an "as is" basis.  The MPEG Software Simulation Group disclaims
10
 
 * any and all warranties, whether express, implied, or statuary, including any
11
 
 * implied warranties or merchantability or of fitness for a particular
12
 
 * purpose.  In no event shall the copyright-holder be liable for any
13
 
 * incidental, punitive, or consequential damages of any kind whatsoever
14
 
 * arising from the use of these programs.
15
 
 *
16
 
 * This disclaimer of warranty extends to the user of these programs and user's
17
 
 * customers, employees, agents, transferees, successors, and assigns.
18
 
 *
19
 
 * The MPEG Software Simulation Group does not represent or warrant that the
20
 
 * programs furnished hereunder are free of infringement of any third-party
21
 
 * patents.
22
 
 *
23
 
 * Commercial implementations of MPEG-1 and MPEG-2 video, including shareware,
24
 
 * are subject to royalty fees to patent holders.  Many of these patents are
25
 
 * general enough such that they are unavoidable regardless of implementation
26
 
 * design.
27
 
 *
28
 
 */
29
 
/* Modifications and enhancements (C) 2000/2001 Andrew Stevens */
30
 
 
31
 
/* These modifications are free software; you can redistribute it
32
 
 *  and/or modify it under the terms of the GNU General Public License
33
 
 *  as published by the Free Software Foundation; either version 2 of
34
 
 *  the License, or (at your option) any later version.
35
 
 *
36
 
 *  This program is distributed in the hope that it will be useful,
37
 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
38
 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
39
 
 *  General Public License for more details.
40
 
 *
41
 
 * You should have received a copy of the GNU General Public License
42
 
 * along with this program; if not, write to the Free Software
43
 
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
44
 
 * 02111-1307, USA.
45
 
 *
46
 
 */
47
 
 
48
 
/* Modifications and enhancements 
49
 
   (C) 2000/2001 Andrew Stevens, Rainer Johanni
50
 
 
51
 
 */
52
 
 
53
 
/* These modifications are free software; you can redistribute it
54
 
 *  and/or modify it under the terms of the GNU General Public License
55
 
 *  as published by the Free Software Foundation; either version 2 of
56
 
 *  the License, or (at your option) any later version.
57
 
 *
58
 
 *  This program is distributed in the hope that it will be useful,
59
 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
60
 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
61
 
 *  General Public License for more details.
62
 
 *
63
 
 * You should have received a copy of the GNU General Public License
64
 
 * along with this program; if not, write to the Free Software
65
 
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
66
 
 * 02111-1307, USA.
67
 
 *
68
 
 */
69
 
 
70
 
 
71
 
#include <config.h>
72
 
#include <stdio.h>
73
 
#include <stdlib.h>
74
 
//#include <unistd.h>
75
 
#include <string.h>
76
 
//#include <pthread.h>
77
 
#include <errno.h>
78
 
#include "global.h"
79
 
 
80
 
#include "mpegconsts.h"
81
 
#include "yuv4mpeg.h"
82
 
 
83
 
#include "ADM_toolkit/ADM_cpuCap.h"
84
 
 
85
 
   /* NOTE: access toframes_read *must* be read-only in other threads
86
 
          once the chunk-reading worker thread has been started.
87
 
   */
88
 
 
89
 
 
90
 
static volatile int frames_read = 0;
91
 
static int last_frame = -1;
92
 
 
93
 
 
94
 
/* Buffers for frame luminance means */
95
 
int luminance_mean_C(uint8_t *frame, int w, int h );
96
 
int luminance_mean_MMX(uint8_t *frame, int w, int h );
97
 
 
98
 
 
99
 
int luminance_mean(uint8_t *frame, int w, int h )
100
 
{
101
 
#if defined( ARCH_X86)  || defined(ARCH_X86_64)
102
 
        if(CpuCaps::hasMMX()) return luminance_mean_MMX(frame,w,h);
103
 
#endif
104
 
        luminance_mean_C(frame,w,h);
105
 
}
106
 
 
107
 
 
108
 
 
109
 
 
110
 
 
111
 
int luminance_mean_C(uint8_t *frame, int w, int h )
112
 
{
113
 
        uint8_t *p = frame;
114
 
        uint8_t *lim = frame + w*h;
115
 
        int sum = 0;
116
 
        while( p < lim )
117
 
        {
118
 
                sum += (p[0] + p[1]) + (p[2] + p[3]) + (p[4] + p[5]) + (p[6] + p[7]);
119
 
                p += 8;
120
 
        }
121
 
        sum=sum/(w*h);
122
 
        return sum;
123
 
}
124
 
#if defined( ARCH_X86)  || defined(ARCH_X86_64)
125
 
// MEANX
126
 
// code borrowed from ffmpeg by means
127
 
 
128
 
static int pix_sum16_mmx(uint8_t * pix, int line_size)
129
 
{
130
 
    const int h=16;
131
 
#ifdef ARCH_X86_64
132
 
    long int rline_size=line_size;
133
 
    long int sum;
134
 
    long int index= -line_size*h;
135
 
#else    
136
 
    int rline_size=line_size;
137
 
    int sum;
138
 
    int index= -line_size*h;
139
 
#endif
140
 
 
141
 
    __asm __volatile(
142
 
                "pxor %%mm7, %%mm7              \n\t"
143
 
                "pxor %%mm6, %%mm6              \n\t"
144
 
                "1:                             \n\t"
145
 
                "movq (%2, %1), %%mm0           \n\t"
146
 
                "movq (%2, %1), %%mm1           \n\t"
147
 
                "movq 8(%2, %1), %%mm2          \n\t"
148
 
                "movq 8(%2, %1), %%mm3          \n\t"
149
 
                "punpcklbw %%mm7, %%mm0         \n\t"
150
 
                "punpckhbw %%mm7, %%mm1         \n\t"
151
 
                "punpcklbw %%mm7, %%mm2         \n\t"
152
 
                "punpckhbw %%mm7, %%mm3         \n\t"
153
 
                "paddw %%mm0, %%mm1             \n\t"
154
 
                "paddw %%mm2, %%mm3             \n\t"
155
 
                "paddw %%mm1, %%mm3             \n\t"
156
 
                "paddw %%mm3, %%mm6             \n\t"
157
 
                "add %3, %1                     \n\t"
158
 
                " js 1b                         \n\t"
159
 
                "movq %%mm6, %%mm5              \n\t"
160
 
                "psrlq $32, %%mm6               \n\t"
161
 
                "paddw %%mm5, %%mm6             \n\t"
162
 
                "movq %%mm6, %%mm5              \n\t"
163
 
                "psrlq $16, %%mm6               \n\t"
164
 
                "paddw %%mm5, %%mm6             \n\t"
165
 
                "movd %%mm6, %0                 \n\t"
166
 
                "and $0xFFFF, %0                \n\t"
167
 
                : "=&r" (sum), "+r" (index)
168
 
                : "r" (pix - index), "r" (rline_size)
169
 
        );
170
 
 
171
 
        return sum;
172
 
}
173
 
int luminance_mean_MMX(uint8_t *frame, int w, int h )
174
 
{
175
 
        uint8_t *p = frame;
176
 
        int mean=0;
177
 
        int x,y;
178
 
 
179
 
        for(y=0; y<h; y+=16)
180
 
        {
181
 
                p=frame+w*y;
182
 
                for(x=0; x<w; x+=16)
183
 
                {
184
 
 
185
 
                        mean+=pix_sum16_mmx(p, w);
186
 
                        p+=16;
187
 
                }
188
 
        }
189
 
        __asm__ ("emms");
190
 
        mean=mean/(w*h);
191
 
        return mean;
192
 
}
193
 
 
194
 
#endif
195
 
// MEANX
196
 
#if 0
197
 
int piperead(int fd, uint8_t *buf, int len)
198
 
{
199
 
   int n, r;
200
 
 
201
 
   r = 0;
202
 
 
203
 
   while(r<len)
204
 
   {
205
 
      n = read(fd,buf+r,len-r);
206
 
      if(n==0) return r;
207
 
      r += n;
208
 
   }
209
 
   return r;
210
 
}
211
 
#endif
212
 
 
213
 
 
214
 
#ifndef PUSH
215
 
/*
216
 
static void read_chunk(void)
217
 
{
218
 
   int n, v, h, i,j, y;
219
 
   y4m_frame_info_t fi;
220
 
 
221
 
 
222
 
   for(j=0;j<READ_CHUNK_SIZE;++j)
223
 
   {
224
 
           if( ctl->parallel_read )
225
 
           {
226
 
                   // Unlock during the actual I/O filling buffers to allow
227
 
                   // the main thread to run if there are still the frames
228
 
                   // it needs.  The main thread atomically signals new_chunk_req
229
 
                   // before waiting on new_chunk_ack.
230
 
                   // This thread atomically signals new_chunk_ack before
231
 
                   // waiting on new_chunk_req.
232
 
                   // Thus neither can suspend without first
233
 
                   // starting the other.
234
 
                   //mjpeg_info( "PRO:  releasing frame buf lock @ %d ", frames_read);
235
 
 
236
 
                   pthread_mutex_unlock( &frame_buffer_lock );
237
 
           }
238
 
      n = frames_read % frame_buffer_size;
239
 
 
240
 
      y4m_init_frame_info (&fi);
241
 
 
242
 
      if ((y = y4m_read_frame_header (istrm_fd, &fi)) != Y4M_OK)
243
 
          {
244
 
                  if( y != Y4M_ERR_EOF )
245
 
                          mjpeg_log (LOG_WARN,
246
 
                                                 "Error reading frame header (%d): code%s!",
247
 
                                                 n,
248
 
                                                 y4m_strerr (n));
249
 
         goto EOF_MARK;
250
 
      }
251
 
 
252
 
      v = opt->vertical_size;
253
 
      h = opt->horizontal_size;
254
 
      for(i=0;i<v;i++)
255
 
         if(piperead(istrm_fd,frame_buffers[n][0]+i*opt->phy_width,h)!=h) goto EOF_MARK;
256
 
          lum_mean[n] = luminance_mean(frame_buffers[n][0], opt->phy_width, opt->phy_height );
257
 
 
258
 
      v = opt->chroma_format==CHROMA420 ?
259
 
                  opt->vertical_size/2 : opt->vertical_size;
260
 
      h = opt->chroma_format!=CHROMA444 ?
261
 
                  opt->horizontal_size/2 : opt->horizontal_size;
262
 
      for(i=0;i<v;i++)
263
 
         if(piperead(istrm_fd,frame_buffers[n][1]+i*opt->phy_chrom_width,h)!=h) goto EOF_MARK;
264
 
      for(i=0;i<v;i++)
265
 
         if(piperead(istrm_fd,frame_buffers[n][2]+i*opt->phy_chrom_width,h)!=h) goto EOF_MARK;
266
 
 
267
 
 
268
 
          if( ctl->parallel_read )
269
 
          {
270
 
                  //
271
 
                  // Lock to atomically signal the availability of additional
272
 
                  // material from a chunk - waking the main thread
273
 
                  // if it suspended because a required frame was
274
 
                  // unavailable
275
 
                  //
276
 
                  //mjpeg_info( "PRO:  waiting for frame buf lock @ %d ", frames_read);
277
 
                  pthread_mutex_lock( &frame_buffer_lock );
278
 
          }
279
 
          ++frames_read;
280
 
 
281
 
          if( ctl->parallel_read )
282
 
          {
283
 
                  //mjpeg_info( "PRO: Signalling new_chunk_ack @ %d", frames_read );
284
 
                  pthread_cond_broadcast( &new_chunk_ack );
285
 
          }
286
 
 
287
 
   }
288
 
 
289
 
   //
290
 
   // When we exit we're holding the lock again so we can
291
 
   // ensure we're waiting on new_chunk_req if the main thread is
292
 
   // currently running.
293
 
   //
294
 
   return;
295
 
 
296
 
   EOF_MARK:
297
 
   mjpeg_debug( "End of input stream detected" );
298
 
   if( ctl->parallel_read )
299
 
   {
300
 
           pthread_mutex_lock( &frame_buffer_lock );
301
 
   }
302
 
   last_frame = frames_read-1;
303
 
   istrm_nframes = frames_read;
304
 
   //mjpeg_info( "Signalling last frame = %d", last_frame );
305
 
   if( ctl->parallel_read )
306
 
   {
307
 
           //mjpeg_info( "PRO: Signalling new_chunk_ack @ %d", frames_read );
308
 
           pthread_cond_broadcast( &new_chunk_ack );
309
 
   }
310
 
 
311
 
}
312
 
 
313
 
 
314
 
*/
315
 
#if 0
316
 
static void *read_chunks_worker(void *_dummy)
317
 
{
318
 
        //mjpeg_info("PRO: requesting frame buf lock" );
319
 
    //mjpeg_info( "PRO: has frame buf lock @ %d ", frames_read );
320
 
    //mjpeg_info( "PRO: Initial fill of frame buf" );
321
 
    pthread_mutex_lock( &frame_buffer_lock );
322
 
    read_chunk();
323
 
        for(;;)
324
 
        {
325
 
                //mjpeg_info( "PRO: has frame buf lock @ %d ", frames_read );
326
 
                //mjpeg_info( "PRO: Waiting for new_chunk_req " );
327
 
                pthread_cond_wait( &new_chunk_req, &frame_buffer_lock );
328
 
                //mjpeg_info( "PRO: new_chunk_req regained frame buf lock @  %d ", frames_read ); 
329
 
                if( frames_read < istrm_nframes ) 
330
 
                {
331
 
                        read_chunk();
332
 
                }
333
 
        }
334
 
        return NULL;
335
 
}
336
 
 
337
 
 
338
 
static void start_worker(void)
339
 
{
340
 
        pthread_attr_t *pattr = NULL;
341
 
 
342
 
#ifdef HAVE_PTHREADSTACKSIZE
343
 
#define MINSTACKSIZE 200000
344
 
        pthread_attr_t attr;
345
 
        size_t stacksize;
346
 
        
347
 
        pthread_attr_init(&attr);
348
 
        pthread_attr_getstacksize(&attr, &stacksize);
349
 
        
350
 
        if (stacksize < MINSTACKSIZE) {
351
 
                pthread_attr_setstacksize(&attr, MINSTACKSIZE);
352
 
        }
353
 
        
354
 
        pattr = &attr;
355
 
#endif
356
 
 
357
 
 
358
 
        if( pthread_create( &worker_thread, pattr, read_chunks_worker, NULL ) != 0 )
359
 
        {
360
 
                mjpeg_error_exit1( "worker thread creation failed: %s", strerror(errno) );
361
 
 
362
 
        }
363
 
 
364
 
}
365
 
#endif
366
 
 /*****************************************************
367
 
 *
368
 
 *  Read another chunk of frames into the frame buffer if the
369
 
 *  specified frame is less than a chunk away from the end of the
370
 
 *  buffer.  This version is for when frame input reading is not
371
 
 *  multi-threaded and just goes ahead and does it.
372
 
 *
373
 
 * N.b. if ctl->parallel_read is active then read_chunk signals/locks
374
 
 * which could cause problems hence the assert!
375
 
 *
376
 
 *****************************************************/
377
 
   
378
 
static void read_chunk_seq( int num_frame )
379
 
{
380
 
    while(frames_read - num_frame < READ_CHUNK_SIZE &&
381
 
          frames_read < istrm_nframes ) 
382
 
    {
383
 
        read_chunk();
384
 
    }
385
 
}
386
 
 
387
 
 /*****************************************************
388
 
 *
389
 
 * Request read worker thread to read a chunk of frame into the frame
390
 
 * buffer if less than a chunk of frames is left after the specified
391
 
 * frame.  Wait for acknowledgement of the reading of a chunk (implying
392
 
 * at least one extra frame added to the buffer) if the specified frame
393
 
 * is not yet in the buffer.
394
 
 *
395
 
 * N.b. *must* be called with ctl->parallel_read active as otherwise it
396
 
 * will thoroughly deadlocked.
397
 
 *
398
 
 *****************************************************/
399
 
#if 0   
400
 
 
401
 
 
402
 
static void read_chunk_par( int num_frame)
403
 
{
404
 
        //mjpeg_info( "CON: requesting frame buf lock");
405
 
        pthread_mutex_lock( &frame_buffer_lock);
406
 
        for(;;)
407
 
        {
408
 
                //mjpeg_info( "CON: has frame buf lock @ %d (%d recorded read)", frames_read,  num_frame );
409
 
                // Activate reader process "on the fly"
410
 
                if( frames_read - num_frame < READ_CHUNK_SIZE && 
411
 
                        frames_read < istrm_nframes )
412
 
                {
413
 
                        //mjpeg_info( "CON: Running low on frames: signalling new_chunk_req" );
414
 
 
415
 
                        pthread_cond_broadcast( &new_chunk_req );
416
 
                }
417
 
                if( frames_read > num_frame  || 
418
 
                        frames_read >= istrm_nframes )
419
 
                {
420
 
                        //mjpeg_info( "CON:  releasing frame buf lock - enough frames to go on with...");
421
 
                        pthread_mutex_unlock( &frame_buffer_lock );
422
 
                        return;
423
 
                }
424
 
                //mjpeg_info( "CON: waiting for new_chunk_ack - too few frames" );
425
 
                pthread_cond_wait( &new_chunk_ack, &frame_buffer_lock );
426
 
                //mjpeg_info( "CON: regained frame buf lock @ %d (%d processed)", frames_read,  num_frame );
427
 
 
428
 
        }
429
 
        
430
 
}
431
 
#endif
432
 
static void load_frame( int num_frame )
433
 
{
434
 
        printf("Push %d\n",num_frame);  
435
 
        if(last_frame>=0 && num_frame>last_frame &&num_frame<istrm_nframes)
436
 
        {
437
 
                mjpeg_error("Internal:readframe: internal error reading beyond end of frames");
438
 
                abort();
439
 
        }
440
 
        
441
 
        if( frames_read == 0)
442
 
        {
443
 
#if 0   
444
 
#ifdef __linux__
445
 
                pthread_mutexattr_t mu_attr;
446
 
                pthread_mutexattr_t *p_attr = &mu_attr;
447
 
                pthread_mutexattr_settype( &mu_attr, PTHREAD_MUTEX_ERRORCHECK );
448
 
 
449
 
#else
450
 
                pthread_mutexattr_t *p_attr = NULL;             
451
 
#endif          
452
 
                pthread_mutex_init( &frame_buffer_lock, p_attr );
453
 
#endif          
454
 
 
455
 
        lum_mean = new int[frame_buffer_size];
456
 
 
457
 
                /*
458
 
          Pre-fill the buffer with one chunk of frames...
459
 
        */
460
 
        /*      if( ctl->parallel_read )
461
 
        {
462
 
                        start_worker();
463
 
            read_chunk_par( num_frame);
464
 
        }
465
 
        else*/
466
 
        {
467
 
            read_chunk_seq( num_frame);
468
 
        }
469
 
 
470
 
        }
471
 
 
472
 
   /* Read a chunk of frames if we've got less than one chunk buffered
473
 
        */
474
 
 
475
 
/*   if( ctl->parallel_read )
476
 
           read_chunk_par( num_frame );
477
 
   else*/
478
 
           read_chunk_seq( num_frame );
479
 
 
480
 
   /* We aren't allowed to go too far behind the last read
481
 
          either... */
482
 
 
483
 
   if( num_frame+static_cast<int>(frame_buffer_size) < frames_read )
484
 
   {
485
 
           mjpeg_error("Internal:readframe: %d internal error - buffer flushed too soon", frame_buffer_size );
486
 
           abort();
487
 
   }
488
 
        printf("Pushed %d %d\n",num_frame,frames_read); 
489
 
 
490
 
        
491
 
}
492
 
int readframe( int num_frame,
493
 
               unsigned char *frame[]
494
 
                )
495
 
{
496
 
   int n;
497
 
 
498
 
   load_frame( num_frame ); 
499
 
   n = num_frame % frame_buffer_size;
500
 
   frame[0] = frame_buffers[n][0];
501
 
   frame[1] = frame_buffers[n][1];
502
 
   frame[2] = frame_buffers[n][2];
503
 
 
504
 
   return 0;
505
 
}
506
 
int frame_lum_mean( int num_frame )
507
 
{
508
 
        int n = num_frame;
509
 
//      printf("lum mean %d\n",num_frame);
510
 
    //
511
 
    // We use this function to probe for the existence of frames
512
 
    // so we clip at the end if the end is already found...
513
 
    //
514
 
        if(  last_frame > 0 && num_frame > last_frame )
515
 
        {
516
 
                n = last_frame;
517
 
        }
518
 
        load_frame( n );
519
 
    //
520
 
    // We may now know where the last frame is...
521
 
    //
522
 
    if( last_frame > 0 && n > last_frame )
523
 
        n = last_frame;
524
 
//      printf("lum mean %d\n",n);
525
 
        return lum_mean[n% frame_buffer_size];
526
 
}
527
 
 
528
 
#endif
529
 
#if 0
530
 
void read_stream_params( unsigned int *hsize,
531
 
                         unsigned int *vsize, 
532
 
                         unsigned int *frame_rate_code,
533
 
                         unsigned int *interlacing_code,
534
 
                         unsigned int *aspect_ratio_code)
535
 
{
536
 
   int n;
537
 
   y4m_ratio_t sar;
538
 
   y4m_stream_info_t si;
539
 
 
540
 
   y4m_init_stream_info (&si);  
541
 
   if ((n = y4m_read_stream_header (istrm_fd, &si)) != Y4M_OK) {
542
 
       mjpeg_log(LOG_ERROR, "Could not read YUV4MPEG2 header: %s!",
543
 
                 y4m_strerr(n));
544
 
      exit (1);
545
 
   }
546
 
 
547
 
   *hsize = y4m_si_get_width(&si);
548
 
   *vsize = y4m_si_get_height(&si);
549
 
   *frame_rate_code = mpeg_framerate_code(y4m_si_get_framerate(&si));
550
 
   *interlacing_code = y4m_si_get_interlace(&si);
551
 
 
552
 
   /* Deduce MPEG aspect ratio from stream's frame size and SAR...
553
 
      (always as an MPEG-2 code; that's what caller expects). */
554
 
   sar = y4m_si_get_sampleaspect(&si);
555
 
   *aspect_ratio_code = mpeg_guess_mpeg_aspect_code(2, sar,
556
 
                                                    *hsize, *vsize);
557
 
}
558
 
#endif
559
 
 
560
 
/*
561
 
 * Local variables:
562
 
 *  c-file-style: "stroustrup"
563
 
 *  tab-width: 4
564
 
 *  indent-tabs-mode: nil
565
 
 * End:
566
 
 */