usage - u ffmpeg
ffmpeg av_seek_frame con AVSEEK_FLAG_ANY causa pantalla gris (2)
En realidad, AVSEEK_FLAG_BACKWARD
indica que desea encontrar el fotograma clave más cercano con una marca de tiempo más pequeña que la que está buscando.
Al utilizar AVSEEK_FLAG_ANY
, obtiene el marco que corresponde exactamente a la marca de tiempo que solicitó. Pero este fotograma puede no ser un fotograma clave, lo que significa que no se puede decodificar por completo. Eso explica su "pantalla gris", que aparece hasta que se alcanza el siguiente fotograma clave.
La solución sería, por lo tanto, buscar hacia atrás usando AVSEEK_FLAG_BACKWARD
y, desde este fotograma clave, leer los cuadros siguientes (por ejemplo, usando av_read_frame()
) hasta llegar al que corresponde a su marca de tiempo. En este punto, su marco se decodificará por completo y ya no aparecerá como una "pantalla gris".
NOTA: Parece que, por alguna razón, av_seek_frame()
usando AVSEEK_FLAG_BACKWARD
devuelve el siguiente fotograma clave cuando el fotograma que estoy buscando es el que está justo antes de este fotograma clave. De lo contrario, devuelve el fotograma clave anterior (que es lo que quiero). Mi solución es cambiar la marca de tiempo que le doy a av_seek_frame()
para asegurarme de que devolverá el fotograma clave antes del fotograma que estoy buscando.
Problema: el código fuente de omxplayer llama al av_seek_frame()
ffmpeg av_seek_frame()
usando el indicador AVSEEK_FLAG_BACKWARD
. Aunque no estoy 100% seguro, creo que esto busca el i-frame más cercano. En cambio, quiero buscar las ubicaciones exactas, por lo que modifiqué el código fuente de modo que el método av_seek_frame()
ahora usa el indicador AVSEEK_FLAG_ANY
. Ahora, cuando se carga la película, aparece una pantalla gris, generalmente durante 1 segundo, durante la cual puedo escuchar el audio. Lo he intentado en varias computadoras (en realidad las estoy sincronizando, por lo tanto, al mismo tiempo) así que no es un incidente aislado. Mi suposición es que buscar marcos no i es computacionalmente más costoso, lo que resulta en la pantalla gris inicial.
Pregunta: Cómo, usando ffmpeg, puedo ordenar al audio que espere hasta que el video esté listo antes de continuar.
Completando la respuesta de JonesV con un código:
void seekFrame(int FrameIndex)
{
// Seek is done on packet dts
int64_t target_dts_usecs = (int64_t)round(frameIndex * (double)_video_stream->r_frame_rate.den / _video_stream->r_frame_rate.num * AV_TIME_BASE);
// Remove first dts: when non zero seek should be more accurate
auto first_dts_usecs = (int64_t)round(_video_stream->first_dts * (double)_video_stream->time_base.num / _video_stream->time_base.den * AV_TIME_BASE);
target_dts_usecs += first_dts_usecs;
int rv = av_seek_frame(_format_ctx, -1, target_dts_usecs, AVSEEK_FLAG_BACKWARD);
if (rv < 0)
throw exception();
avcodec_flush_buffers(_codec_ctx);
}
Luego puede comenzar a descodificar comprobando AVPacket.dts
contra dts de destino originales, calculados en AVStream.time_base
. Tan pronto como alcances el objetivo dts, el siguiente marco decodificado debe ser el marco deseado.