Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





Ogg por streaming sin que me tirones

Iniciado por Pogacha, 03 de Noviembre de 2006, 12:13:15 PM

« anterior - próximo »

Pogacha

Que tal,
Como puedo hacer para ejecutar ogg por streaming sin que me de tirones?

O sea uso Direct Sound y la libreria ogg.

He probado hacer un buffer Direct Sound y particionarlo en N secciones.
Tomo la posicion de ejecucion y veo si se paso a otra sección, si fue así relleno la posicion anterior(es) con la informacion que obtengo del ogg a traves de un Lock / ov_read() / Unlock

Si hago un buffer grande (1 mega) y lo parto en 2 o 4, o sea, que me queden secciones grandes, el sonido me sale bien, pero cada dos segundos el programa me pega un tiron (pequeño congelamiento). Si hago secciones mas pequeñas el sonido me sale mordido, en realidad con estatica.
He probado tirar otro hilo y darle muchos Sleep(0) y/o Sleep(10).

En teoria lo que tendria que hacer seria tener un buffer de 1 segundo partido en 64 partes e ir leyendolas de apoquito en el otro thread, pero igual no me funciona como quiero ... o me pega tironcitos o me sale mal el sonido

Tengo un pentium 3 750 con lo cual deberia sobrar para ejecutar musica comprimida. He visto andando juegos 3d que utilizaban ejecución mp3 en la misma maquina.

Experiencias sobre el tema?

synchrnzr

CitarExperiencias sobre el tema?

Pues yo mismo ¿cómo realimentas los buffers y cómo detectas que ya puedes llenar un buffer agotado?

sync

marcode

CitarEn teoria lo que tendria que hacer seria tener un buffer de 1 segundo partido en 64 partes e ir leyendolas de apoquito en el otro thread, pero igual no me funciona como quiero ... o me pega tironcitos o me sale mal el sonido
Yo creo que con un buffer de 2 segundos sería suficiente.

Cargas el primer segundo, cuando empieza a reproducir cargas el segundo. Y cuando a pasado la mitad vuelves a cargar el primero, así sucesivamente.

Imagino que haciendo pruebas obtendrás el tamaño y tiempos de carga adecuados.
size=9]afortunadamente siempre ha habido alguien dispuesto a reinventar la rueda, de lo contrario seguiríamos usando un disco de piedra con un agujero.[/size]

Pogacha

CitarPues yo mismo ¿cómo realimentas los buffers y cómo detectas que ya puedes llenar un buffer agotado?
Tengo una funcion update que se llama regularmente una vez por frame o constantemente en la version "hilo aparte".

Muy parecido a esto:

void OggPlayer::Update()
{
   DWORD pos;

   pDSB->GetCurrentPosition(&pos, NULL);

   nCurSection = pos<BUFSIZE?0:1;

   // section changed?
   if (nCurSection != nLastSection)
   {
       if (bDone && !bLoop)
           Stop();

       // gotta use this trick 'cause otherwise there wont be played all bits
       if (bAlmostDone && !bLoop)
           bDone = true;

       DWORD   size = BUFSIZE;
       char    *buf;

       // fill the section we just left
       pDSB->Lock( nLastSection*BUFSIZE, size, (LPVOID*)&buf, &size, NULL, NULL, 0 );

       DWORD   pos = 0;
       int     sec = 0;
       int     ret = 1;
               
       while(ret && pos<size)
       {
           ret = ov_read(&vf, buf+pos, size-pos, 0, 2, 1, &sec);
           pos += ret;
       }

       // reached the and?
       if (!ret && bLoop)
       {
           // we are looping so restart from the beginning
           // NOTE: sound with sizes smaller than BUFSIZE may be cut off

           ret = 1;
           ov_pcm_seek(&vf, 0);
           while(ret && pos<size)
           {
               ret = ov_read(&vf, buf+pos, size-pos, 0, 2, 1, &sec);
               pos += ret;
           }
       }
       else if (!ret && !(bLoop))
       {
           // not looping so fill the rest with 0
           while(pos<size)
               *(buf+pos)=0; pos ++;

           // and say that after the current section no other sectin follows
           bAlmostDone = true;
       }
               
       pDSB->Unlock( buf, size, NULL, NULL );
   
       nLastSection = nCurSection;
   }
}


CitarYo creo que con un buffer de 2 segundos sería suficiente.

Cargas el primer segundo, cuando empieza a reproducir cargas el segundo. Y cuando a pasado la mitad vuelves a cargar el primero, así sucesivamente.
Haciendo eso me pega unos tirones de muerte!

AK47

Puedes crear un hilo para tal menester, que este bloqueado en espera del evento que DirectSound activa cuando el puntero del buffer ha llegado a su fin o algo así, mirate la documentación. Además aprovecharias otra CPU en caso de que estuviera presente :)

Pogacha

He probado con otro hilo pero los resultados son similares...

AK47

Has probado a tenerlo bloqueado a la espera del evento de DirectSound?

Zaelsius

Yo tuve problemas similares este verano.. a ver si luego arranco el PC, miro el código y me acuerdo de dónde estaba mi problema. De todas maneras la técnica más común es la que comenta Marcode, con un búfer de 1 o 2 segundos.

Pogacha

No realmente ... no utilizo los eventos de DSound.
Simplemente leo por donde va escribiendo y si puedo escribir en la mitad otra mitad del buffer entonces.

marcode

Ten en cuenta que hay dos punteros diferentes, uno de reproducción y otro de escritura ligeramente adelantado donde es seguro escribir. El método GetCurrentPosition te devuelve los dos punteros.

Te puede estar pasando que si escribes cuando el puntero de escritura a alcanzado el bloque siguiente destruyas datos que todavía se están reproduciendo porque el puntero de lectura todavía permanece en el bloque anterior que está en reproducción.

¿Te pasa lo mismo con audio sin comprimir?, eso también puede aclarar muchas cosas.
size=9]afortunadamente siempre ha habido alguien dispuesto a reinventar la rueda, de lo contrario seguiríamos usando un disco de piedra con un agujero.[/size]

AK47

Lo de los eventos es muy facil, simplemente después de llenar el buffer, llama a WaitForMultipleObjects con los parametros adecuados (un evento de DirectSoundBuffer y otro tuyo, para desbloquear el hilo y cerrarlo cuando acabe el programa). Esto hará que se bloquee hasta que salte algún evento, consumiendo 0% de CPU. Si hay que llenar otra vez el buffer, se llena y a bloquearse de nuevo :)

Pogacha

Los problemas son solo con el Ogg streaming.

Bueno ... tengo muchas cosas para probar entonces ...
Haré las pruebas y luego les comento los resultados.

Gracias

synchrnzr

Hay varias cosillas que no me gustan ahí. Algunas de las más gordas son estas:

- GetCurrentPosition() devuelve valores incorrectos con los buffers hardware. Fuerza que los buffers se gestionen software al crearlos.

- No es recomendable mantener tanto rato el bloqueo sobre el buffer. Descomprime la información a parte, bloquea el buffer y cópiala. Vigila que la parte del buffer que vas a bloquear no se solape con la parte que se está reproduciendo.

- Ojo con el ov_read(), es muy delicado para los tamaños que acepta, podría darte cortes y generarte ruidos. Si el tamaño que utilizas no es potencia de 2, comprueba siempre el tamaño que ha descomprimido.

- Te recomiendo que utilices las notificaciones de DirectSound, es mucho más cómodo y sencillo, aunque a priori te pueda echar un poco para atrás.

- 1 seg. de buffer me parece un tamaño sobrado. Nunca es problema que sobre, el problema es que el buffer se quede corto y no te dé tiempo a rellenarlo.

sync

Pogacha

Esa es una buena guia!

Voy a probar todo!
Muchas gracias.

Pogacha

Ok, he probado con:
1 Buffer de 1 megas dividido en 4 secciones.
Hilo aparte pero minimizando el tiempo de lock.
En definitiva un triple buffer.
El rendimiento es bastante bueno pero aun hay micro tirones cada 1 segundo.
No me convence para nada pues el rendimiento podria variar entonces ...
Me queda probar ir al tema de eventos.
Luego les comento.






Stratos es un servicio gratuito, cuyos costes se cubren en parte con la publicidad.
Por favor, desactiva el bloqueador de anuncios en esta web para ayudar a que siga adelante.
Muchísimas gracias.