Pregunta

Me estoy agarrando fotogramas de vídeo de la cámara a través de v4l, y necesito transcodificarlos en formato MPEG4 a transmitir sucesivamente ellas a través de RTP.

Todo realidad "obras", pero hay algo que no, mientras que re-codificación: el flujo de entrada produce 15 fps, mientras que la salida es a 25fps, y cada cuadro de entrada se convierte en una secuencia único objeto de vídeo (i verificado esto con una sencilla comprobación en el flujo de bits de salida). Supongo que el receptor es analizar correctamente el flujo de bits MPEG4 pero la paquetización RTP es de alguna manera equivocada. ¿Cómo se supone que voy a dividir el flujo de bits codificado en uno o más AVPacket? Tal vez me falta lo obvio y yo sólo hay que buscar marcadores de trama B / P, pero creo que no estoy usando la API de codificar correctamente.

Este es un extracto de mi código, que se basa en las muestras ffmpeg disponibles:

// input frame
AVFrame *picture;
// input frame color-space converted
AVFrame *planar;
// input format context, video4linux2
AVFormatContext *iFmtCtx;
// output codec context, mpeg4
AVCodecContext *oCtx;
// [ init everything ]
// ...
oCtx->time_base.num = 1;
oCtx->time_base.den = 25;
oCtx->gop_size = 10;
oCtx->max_b_frames = 1;
oCtx->bit_rate = 384000;
oCtx->pix_fmt = PIX_FMT_YUV420P;

for(;;)
{
  // read frame
  rdRes = av_read_frame( iFmtCtx, &pkt );
  if ( rdRes >= 0 && pkt.size > 0 )
  {
    // decode it
    iCdcCtx->reordered_opaque = pkt.pts;
    int decodeRes = avcodec_decode_video2( iCdcCtx, picture, &gotPicture, &pkt );
    if ( decodeRes >= 0 && gotPicture )
    {
      // scale / convert color space
      avpicture_fill((AVPicture *)planar, planarBuf.get(), oCtx->pix_fmt, oCtx->width, oCtx->height);
      sws_scale(sws, picture->data, picture->linesize, 0, iCdcCtx->height, planar->data, planar->linesize);
      // encode
      ByteArray encBuf( 65536 );
      int encSize = avcodec_encode_video( oCtx, encBuf.get(), encBuf.size(), planar );
      // this happens every GOP end
      while( encSize == 0 )
        encSize = avcodec_encode_video( oCtx, encBuf.get(), encBuf.size(), 0 );
      // send the transcoded bitstream with the result PTS
      if ( encSize > 0 )
        enqueueFrame( oCtx->coded_frame->pts, encBuf.get(), encSize );
    }
  }
}
¿Fue útil?

Solución

La solución más sencilla sería utilizar dos hilos. En primer hilo haría todas las cosas descritas en su pregunta (decodificación, la conversión de escala / espacio de color, codificación). Parcialmente marcos transcodificados se escriben en la cola intermedia compartida con el segundo hilo. La duración máxima de esta cola sería en este caso particular (la conversión de menor a mayor tasa de bits) 1 marco. Segundo hilo sería la lectura en marcos de bucle de cola de entrada como esta:

void FpsConverter::ThreadProc()
{

timeBeginPeriod(1);
DWORD start_time = timeGetTime();
int frame_counter = 0;
while(!shouldFinish()) {
    Frame *frame = NULL;
    DWORD time_begin = timeGetTime();
    ReadInputFrame(frame);
    WriteToOutputQueue(frame);
    DWORD time_end = timeGetTime();
    DWORD next_frame_time = start_time + ++frame_counter * frame_time;
    DWORD time_to_sleep = next_frame_time - time_end;
    if (time_to_sleep > 0) {
        Sleep(time_to_sleep);
    }
}
timeEndPeriod(1);
}

Cuando la carga de la CPU es suficiente y mayor fidelidad y suavidad se requiere que usted podría calcular trama de salida no sólo de un cuadro, pero más fotogramas por algún tipo de interpolación (similar a las técnicas utilizadas en los códecs MPEG). La marca de tiempo más cerca trama de salida de marca de tiempo de trama de entrada, más peso se debe asignar a esta trama de entrada en particular.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top