Homesource Forums

Homeworld Source Editing Talk
It is currently Mon Sep 25, 2017 10:54 pm

All times are UTC - 5 hours




Post new topic Reply to topic  [ 8 posts ] 
Author Message
 Post subject: A couple of patches
PostPosted: Thu Jul 17, 2008 2:17 pm 
Offline

Joined: Mon Jul 07, 2008 6:24 pm
Posts: 14
Sound crackles on certain chipsets, this is due to SDL setting aspec samples to a number that isn't a multiple of MIX_BLOCK_SIZE, this overflows SDL's buffer causing crackling during playback and segfaults on SDL audio cleanup. The following patch simply adds an intermediary buffer to allow filling SDL's buffer to an arbitrary requested size from MIX_BLOCK_SIZE chunks.

Code:
diff -urN homeworld.orig/src/SDL/smixer.c homeworld/src/SDL/smixer.c
--- homeworld.orig/src/SDL/smixer.c   2008-07-08 18:26:09.000000000 +0100
+++ homeworld/src/SDL/smixer.c   2008-07-09 00:45:50.000000000 +0100
@@ -824,19 +824,35 @@
    Outputs      :
    Return      :
 ----------------------------------------------------------------------------*/   
+static Uint8 oddbuf[MIX_BLOCK_SIZE];
+static udword oddbufpos = 0;
+
 void isoundmixerqueueSDL(Uint8 *stream, int len)
 {
    udword size_written = 0;
 
-   dbgAssertOrIgnore((len % MIX_BLOCK_SIZE) == 0);
+   /* dbgAssertOrIgnore((len % MIX_BLOCK_SIZE) == 0); */
+
+   if (oddbufpos > 0) {
+      memcpy(stream, oddbuf + oddbufpos, MIX_BLOCK_SIZE - oddbufpos);
+      size_written += MIX_BLOCK_SIZE - oddbufpos;
+      oddbufpos = 0;
+   }
 
    while (size_written < len) {
       // process 256 samples, 16-bit (independent of # of channels)
-      isoundmixerprocess(stream + size_written,
-            FQ_SIZE * sizeof(short),
-            NULL, 0);
-      /* write(adump_fd, lpvWritePtr, FQ_SIZE * sizeof(short)); */
-      size_written += MIX_BLOCK_SIZE;
+      if (size_written + MIX_BLOCK_SIZE > len) {
+         isoundmixerprocess(oddbuf, FQ_SIZE * sizeof(short), NULL, 0);
+         oddbufpos = len - size_written;
+         memcpy(stream + size_written, oddbuf, oddbufpos);
+         size_written += oddbufpos;
+      } else {
+         isoundmixerprocess(stream + size_written,
+               FQ_SIZE * sizeof(short),
+               NULL, 0);
+         /* write(adump_fd, lpvWritePtr, FQ_SIZE * sizeof(short)); */
+         size_written += MIX_BLOCK_SIZE;
+      }
    }
 }
 
diff -urN homeworld.orig/src/SDL/soundlow.c homeworld/src/SDL/soundlow.c
--- homeworld.orig/src/SDL/soundlow.c   2008-07-08 18:26:08.000000000 +0100
+++ homeworld/src/SDL/soundlow.c   2008-07-08 18:18:15.000000000 +0100
@@ -241,7 +241,8 @@
        result = SOUND_OK;
    }
 
-   dbgAssertOrIgnore(aspec.samples == SDL_BUFFERSIZE);
+   /* extra buffer added to smixer, not necessary anymore */
+   /* dbgAssertOrIgnore(aspec.samples == SDL_BUFFERSIZE); */
 
    return result;
 }


The next patch implements fullscreen playback of videos by first scaling in sw to a sufficiently large texture, then using opengl to render the texture at the screen resolution (this method is also utilized by quake 2 incidentally). It also fixes playback timing issues (in short, SDL_GetTicks is accurate, SDL_Delay isn't), and comments out the ffmpeg CODEC_CAP_TRUNCATED stuff, as it corrupts the video output.

Code:
--- homeworld.orig/src/SDL/avi.c   2008-07-08 18:26:08.000000000 +0100
+++ homeworld/src/SDL/avi.c   2008-07-08 23:21:29.000000000 +0100
@@ -244,12 +244,91 @@
 }
 
 #ifdef HW_ENABLE_MOVIES
+static GLint strtex;
+static int texinit = 0;
+
+static GLint maxtex = -1;
+static int maxTextureSize() {
+   if (maxtex < 0)
+      glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxtex);
+   return maxtex;
+}
+
+static void Draw_Stretch (int x, int y, int w, int h, int cols, int rows, char *data)
+{
+   int texsize;
+
+   texsize = cols > rows ? cols : rows;
+   while (texsize != (texsize & -texsize))
+      texsize += (texsize & -texsize);
+   while (texsize > maxTextureSize())
+      texsize /= 2;
+
+   unsigned   image32[texsize*texsize];
+   unsigned int   *source, *dest;
+   float      hscale;
+   int      i, j, row, trows, frac, fracstep;
+   float      t;
+
+   if (!texinit) {
+      glGenTextures(1, &strtex);
+      texinit = 1;
+   }
+   glBindTexture(GL_TEXTURE_2D, strtex);
+
+   if (rows<=texsize)
+   {
+      hscale = 1;
+      trows = rows;
+   }
+   else
+   {
+      hscale = rows/texsize;
+      trows = texsize;
+   }
+   t = rows*hscale / texsize - 1.0/512.0;
+
+   for (i=0 ; i<trows ; i++)
+   {
+      row = (int)(i*hscale);
+      if (row > rows)
+         break;
+      source = ((unsigned int*)data) + cols*row;
+      dest = &image32[i*texsize];
+      fracstep = cols*0x10000/texsize;
+      frac = fracstep >> 1;
+      for (j=0 ; j<texsize ; j++)
+      {
+         dest[j] = source[frac>>16];
+         frac += fracstep;
+      }
+   }
+
+   glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB, texsize, texsize, 0, GL_BGRA, GL_UNSIGNED_BYTE, image32);
+   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+   glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+   glEnable(GL_TEXTURE_2D);
+
+   glBegin (GL_QUADS);
+   glTexCoord2f (1.0/512.0, 1.0/512.0);
+   glVertex2f (x, y);
+   glTexCoord2f (511.0/512.0, 1.0/512.0);
+   glVertex2f (x+w, y);
+   glTexCoord2f (511.0/512.0, t);
+   glVertex2f (x+w, y+h);
+   glTexCoord2f (1.0/512.0, t);
+   glVertex2f (x, y+h);
+   glEnd ();
+
+}
 
 //void aviDisplayFrame( AVFrame *pFrameRGB )
 void aviDisplayFrame( AVPicture *pFrameRGB, int w, int h )
 {
 
-    int x, y;
+/*    int x, y;
 
     x = (MAIN_WindowWidth  - w) / 2;
     y = (MAIN_WindowHeight  - h) / 2;
@@ -274,8 +353,13 @@
 
 
 //  dbgMessagef("aviDisplayFrame: R=%s  G=%s  B=%s", testR, testG, testB);
-//   dbgMessagef("aviDisplayFrame: R=%s", testR);
+//   dbgMessagef("aviDisplayFrame: R=%s", testR);*/
 
+    aviReverseRGBA( pFrameRGB->data[0], w, h );
+
+    animAviSetup(TRUE);
+    Draw_Stretch(0, 0, MAIN_WindowWidth, MAIN_WindowHeight, w, h, pFrameRGB->data[0]);
+    animAviSetup(FALSE);
 
 /*
     if (g_pbmi != NULL)
@@ -333,7 +417,10 @@
     int numBytes;
     int frameFinished;
     int event_res = 0;
-    Uint32 local_time, local_last_time, local_interval;
+#if AVI_VERBOSE_LEVEL >= 2
+    Uint32 start_time = SDL_GetTicks();
+#endif
+    Uint32 last_time = SDL_GetTicks();
     SDL_Event e;
     char * buffer;
 //    AVFrame *pFrameRGB;
@@ -372,12 +459,9 @@
 
             animAviDecode(frame);
 
-            local_time= SDL_GetTicks();
-            local_interval = local_time - local_last_time ;
-            local_last_time = local_time ;
-            if ((local_interval > 0) && (local_interval < 76)) {
-                SDL_Delay(77 - local_interval);  //Closer...  :)
-            }
+            while (SDL_GetTicks() - last_time < 67)
+                SDL_Delay(1);
+            last_time = SDL_GetTicks();
 
             speechEventUpdate();   //Keep this it works. :)
             rndClearToBlack();
@@ -400,6 +484,9 @@
 
     }
 
+#if AVI_VERBOSE_LEVEL >= 2
+dbgMessagef("aviPlayLoop: play_time=%d ", SDL_GetTicks() - start_time);
+#endif
     // Clear Allocs
 
     av_free(buffer);
@@ -511,10 +598,11 @@
 dbgMessagef("aviStart: Codec required: %s.", pCodec->name);
 #endif
 
-    if(pCodec->capabilities & CODEC_CAP_TRUNCATED) {
+/* this results in corrupted video */
+/*    if(pCodec->capabilities & CODEC_CAP_TRUNCATED) {
         dbgMessage("Problem with the codec dealing with truncated frames.");
         pCodecCtx->flags|=CODEC_FLAG_TRUNCATED;
-    }
+    }*/
 
 // Open codec
     if(avcodec_open(pCodecCtx, pCodec)<0) {


And finally, a trivial patch to reenable the intro videos.

Code:
--- homeworld.orig/src/SDL/utility.c   2008-07-08 18:26:09.000000000 +0100
+++ homeworld/src/SDL/utility.c   2008-07-08 18:18:15.000000000 +0100
@@ -4129,7 +4129,7 @@
     utySet2(SS2_BabyCallBackRegistry);
 
 
-// aviIntroPlay();  // PlaceHolder for playing the intro Movies (Relic && Sierra)
+    aviIntroPlay();  // PlaceHolder for playing the intro Movies (Relic && Sierra)
 
     universeInit();
     utySet(SSA_Universe);


Top
 Profile  
 
 Post subject: Re: A couple of patches
PostPosted: Fri Jul 18, 2008 4:32 am 
Offline
coder

Joined: Wed Nov 15, 2006 8:15 am
Posts: 100
pseudonym404,

Thanks a lot for these patches. I will test them tomorrow.

Very good job to have figure out where the sound crackling probleme comes from! :)

Don't you have a svn account? It would be easier for you to commit your changes.


Top
 Profile  
 
 Post subject: Re: A couple of patches
PostPosted: Fri Jul 18, 2008 6:27 pm 
Offline

Joined: Mon Jul 07, 2008 6:24 pm
Posts: 14
I'm currently talking to lmop (via pm) about svn write access.

The assert I commented out in soundlow.c was a big red flag to the cause of the sound issue if you have an affected chipset and a debug build (and especially if you've come across similar problems before). ;)

I think it's something to do with many recent cheap/onboard chipsets only supporting a few high frequencies in hardware (48000 and up), resulting in SDL wanting odd sized chunks of data, anything supporting 11025, 22050 or 44100 in hardware likely won't be affected.

I'm currently messing with reverse engineering the missing sound code, not got very far yet, but due to minimal use of effects, only fqMix from fqeffect.o strictly needs implementing to get sound output, and that's as simple as:

Code:
int fqMix(float *aPBlock, float *aSBlock, float fLev) {
   int i;
   for (i=0; i<FQ_SIZE; i++)
      aPBlock[i] += aSBlock[i] * fLev;
   return OK;
}


fqDequantBlock (fquant.o) and fqWriteTBlock (fqcodec.o) are going to be a fair bit harder, but with just those three functions replaced, and dummy placeholders for the rest, sound output should work without requiring the x86 only objects (I'd eventually like to make an x86_64 build, but that's a long way off).

edit: fqWriteTBlock wasn't actually too hard, but fqDecBlock is also needed, which needs fqDecOver, which needs idct, which needs fft... fun... if I can find and implement a suitable inverse DCT algorithm, I can handle fqDecBlock and fqDecOver though.

more editing: only fqeffect is getting placeholder functions, everything else that's called from smixer.c is needed. I currently have working: fqWriteTBlock, fqDecBlock, fqDecOver and fqMix. I still need to implement: fqInitDequant, fqDequantBlock, Initdct and idct. I'm basically about half way though (in one overnight session, go me) ;)

yet more editing: I finally replaced all the functions that make sound happen, half the effects are still missing, but I'm working on it. idct was a nightmare, several inexplicable * -1 were needed, which I finally worked out poring over lots and lots of buffer dumps from key points (sounds like it's submerged in liquid metal without them). ;)

NB. This is just the current contents of my head regarding homeworld, no promises ;)


Top
 Profile  
 
 Post subject:
PostPosted: Mon Aug 04, 2008 3:35 pm 
Offline
coder

Joined: Mon Jan 29, 2007 2:45 pm
Posts: 61
The fullscreen video patch (r653) is horribly slow. It also slows down the campaign videos, which used to run reasonably well.


Top
 Profile  
 
 Post subject: Re: A couple of patches
PostPosted: Fri Aug 08, 2008 6:48 pm 
Offline

Joined: Mon Jul 07, 2008 6:24 pm
Posts: 14
You might be better hardcoding
[code]static GLint maxtex = 512;[code]
if you're having performance problems, as it's likely due to the current code software scaling to a 1024x1024 texture to avoid downscaling 640 to 512.


Top
 Profile  
 
 Post subject: Re: A couple of patches
PostPosted: Fri Aug 15, 2008 5:47 am 
Offline
coder

Joined: Mon Jan 29, 2007 2:45 pm
Posts: 61
Hardcoding maxtex did speed up things somewhat, although it remains sluggish. But I do not understand why we should bother with this sort of detail instead of simply letting ffmpeg scale to the right size and glDrawPixels the frame like we used to.


Top
 Profile  
 
 Post subject: Re: A couple of patches
PostPosted: Tue Sep 23, 2008 1:02 pm 
Offline

Joined: Mon Jul 07, 2008 6:24 pm
Posts: 14
Before I changed to texture rendering, the video wasn't being scaled at all for me - and fullscreen glDrawPixels is extremely slow in many implementations. Texture rendering probably should be capped to a maximum texture size of 512 though, as with further experimenting it looks like most older and/or onboard gfx chipsets just can't handle higher at a tolerable framerate. Video rendered to a 512x512 texture, scaled to fullscreen definitely seems to take less resources than a largish fleet later in the game (based on experiments with a 1.6GHz Atom N270 with GMA950 gfx chipset).


Top
 Profile  
 
 Post subject: Re: A couple of patches
PostPosted: Thu Oct 02, 2008 2:52 am 
Offline
coder

Joined: Mon Jan 29, 2007 2:45 pm
Posts: 61
Hm, yeah, it does not seem to get scaled. I was just running in 640x480 so I did not notice.

On my hardware (Radeon 9250) glDrawPixels is very fast with the campaign videos but extremely slow with the intros. I haven't had time to search for the reason of this huge difference. Rendering with 512x512 textures is sort of uniformly sluggish. I suspect the fastest way to scale video would be with Xv but that is inconveniently platform-dependent. We could also just switch video modes with SDL instead of scaling.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 8 posts ] 

All times are UTC - 5 hours


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
cron
Powered by phpBB® Forum Software © phpBB Group