FFmpeg avcodec_decode_video2 декодирует пакет HD-видео RTSP H264 в видеоизображение с ошибкой - PullRequest
0 голосов
/ 28 мая 2018

Я использовал FFmpeg библиотеку version 4.0, чтобы иметь простую программу на C ++, в которой есть поток для получения RTSP H264 видеоданных с IP-камеры и отображения их в окне программы.

Код этой темы следующий:

DWORD WINAPI GrabbProcess(LPVOID lpParam)
// Grabbing thread
{
  DWORD i;
  int ret = 0, nPacket=0;
  FILE *pktFile;
  // Open video file
  pFormatCtx = avformat_alloc_context();
  if(avformat_open_input(&pFormatCtx, nameVideoStream, NULL, NULL)!=0)
      fGrabb=-1; // Couldn't open file
  else
  // Retrieve stream information
  if(avformat_find_stream_info(pFormatCtx, NULL)<0)
      fGrabb=-2; // Couldn't find stream information
  else
  {
      // Find the first video stream
      videoStream=-1;
      for(i=0; i<pFormatCtx->nb_streams; i++)
        if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO)
        {
          videoStream=i;
          break;
        }
      if(videoStream==-1)
          fGrabb=-3; // Didn't find a video stream
      else
      {
          // Get a pointer to the codec context for the video stream
          pCodecCtxOrig=pFormatCtx->streams[videoStream]->codec;
          // Find the decoder for the video stream
          pCodec=avcodec_find_decoder(pCodecCtxOrig->codec_id);
          if(pCodec==NULL)
              fGrabb=-4; // Codec not found
          else
          {
              // Copy context
              pCodecCtx = avcodec_alloc_context3(pCodec);
              if(avcodec_copy_context(pCodecCtx, pCodecCtxOrig) != 0)
                  fGrabb=-5; // Error copying codec context
              else
              {
                  // Open codec
                  if(avcodec_open2(pCodecCtx, pCodec, NULL)<0)
                      fGrabb=-6; // Could not open codec
                  else
                  // Allocate video frame for input
                  pFrame=av_frame_alloc();
                  // Determine required buffer size and allocate buffer
                  numBytes=avpicture_get_size(pCodecCtx->pix_fmt, pCodecCtx->width,
                      pCodecCtx->height);
                  buffer=(uint8_t *)av_malloc(numBytes*sizeof(uint8_t));
                  // Assign appropriate parts of buffer to image planes in pFrame
                  // Note that pFrame is an AVFrame, but AVFrame is a superset
                  // of AVPicture
                  avpicture_fill((AVPicture *)pFrame, buffer, pCodecCtx->pix_fmt,
                      pCodecCtx->width, pCodecCtx->height);

                  // Allocate video frame for display
                  pFrameRGB=av_frame_alloc();
                  // Determine required buffer size and allocate buffer
                  numBytes=avpicture_get_size(AV_PIX_FMT_RGB24, pCodecCtx->width,
                      pCodecCtx->height);
                  bufferRGB=(uint8_t *)av_malloc(numBytes*sizeof(uint8_t));
                  // Assign appropriate parts of buffer to image planes in pFrameRGB
                  // Note that pFrameRGB is an AVFrame, but AVFrame is a superset
                  // of AVPicture
                  avpicture_fill((AVPicture *)pFrameRGB, bufferRGB, AV_PIX_FMT_RGB24,
                      pCodecCtx->width, pCodecCtx->height);
                  // initialize SWS context for software scaling to FMT_RGB24
                  sws_ctx_to_RGB = sws_getContext(pCodecCtx->width,
                      pCodecCtx->height,
                      pCodecCtx->pix_fmt,
                      pCodecCtx->width,
                      pCodecCtx->height,
                      AV_PIX_FMT_RGB24,
                      SWS_BILINEAR,
                      NULL,
                      NULL,
                      NULL);

                  // Allocate video frame (grayscale YUV420P) for processing
                  pFrameYUV=av_frame_alloc();
                  // Determine required buffer size and allocate buffer
                  numBytes=avpicture_get_size(AV_PIX_FMT_YUV420P, pCodecCtx->width,
                      pCodecCtx->height);
                  bufferYUV=(uint8_t *)av_malloc(numBytes*sizeof(uint8_t));
                  // Assign appropriate parts of buffer to image planes in pFrameYUV
                  // Note that pFrameYUV is an AVFrame, but AVFrame is a superset
                  // of AVPicture
                  avpicture_fill((AVPicture *)pFrameYUV, bufferYUV, AV_PIX_FMT_YUV420P,
                      pCodecCtx->width, pCodecCtx->height);
                  // initialize SWS context for software scaling to FMT_YUV420P
                  sws_ctx_to_YUV = sws_getContext(pCodecCtx->width,
                      pCodecCtx->height,
                      pCodecCtx->pix_fmt,
                      pCodecCtx->width,
                      pCodecCtx->height,
                      AV_PIX_FMT_YUV420P,
                      SWS_BILINEAR,
                      NULL,
                      NULL,
                      NULL);
                RealBsqHdr.biWidth = pCodecCtx->width;
                RealBsqHdr.biHeight = -pCodecCtx->height;
              }
          }
      }
  }
  while ((fGrabb==1)||(fGrabb==100))
  {
      // Grabb a frame
      if (av_read_frame(pFormatCtx, &packet) >= 0)
      {
        // Is this a packet from the video stream?
        if(packet.stream_index==videoStream)
        {
            // Decode video frame
            int len = avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
            nPacket++;
            // Did we get a video frame?
            if(frameFinished)
            {
                // Convert the image from its native format to YUV
                sws_scale(sws_ctx_to_YUV, (uint8_t const * const *)pFrame->data,
                    pFrame->linesize, 0, pCodecCtx->height,
                    pFrameYUV->data, pFrameYUV->linesize);
                // Convert the image from its native format to RGB
                sws_scale(sws_ctx_to_RGB, (uint8_t const * const *)pFrame->data,
                    pFrame->linesize, 0, pCodecCtx->height,
                    pFrameRGB->data, pFrameRGB->linesize);
                HDC hdc=GetDC(hWndM);
                SetDIBitsToDevice(hdc, 0, 0, pCodecCtx->width, pCodecCtx->height,
                    0, 0, 0, pCodecCtx->height,pFrameRGB->data[0], (LPBITMAPINFO)&RealBsqHdr, DIB_RGB_COLORS);
                ReleaseDC(hWndM,hdc);
                av_frame_unref(pFrame);
            }
        }
        // Free the packet that was allocated by av_read_frame
        av_free_packet(&packet);
      }
   }
   // Free the org frame
  av_frame_free(&pFrame);
  // Free the RGB frame
  av_frame_free(&pFrameRGB);
  // Free the YUV frame
  av_frame_free(&pFrameYUV);

  // Close the codec
  avcodec_close(pCodecCtx);
  avcodec_close(pCodecCtxOrig);

  // Close the video file
  avformat_close_input(&pFormatCtx);
  avformat_free_context(pFormatCtx);

  if (fGrabb==1)
      sprintf(tmpstr,"Grabbing Completed %d frames", nCntTotal);
  else if (fGrabb==2)
      sprintf(tmpstr,"User break on %d frames", nCntTotal);
  else if (fGrabb==3)
      sprintf(tmpstr,"Can't Grabb at frame %d", nCntTotal);
  else if (fGrabb==-1)
      sprintf(tmpstr,"Couldn't open file");
  else if (fGrabb==-2)
      sprintf(tmpstr,"Couldn't find stream information");
  else if (fGrabb==-3)
      sprintf(tmpstr,"Didn't find a video stream");
  else if (fGrabb==-4)
      sprintf(tmpstr,"Codec not found");
  else if (fGrabb==-5)
      sprintf(tmpstr,"Error copying codec context");
  else if (fGrabb==-6)
      sprintf(tmpstr,"Could not open codec");
  i=(UINT) fGrabb;
  fGrabb=0;
  SetWindowText(hWndM,tmpstr);
  ExitThread(i);
  return 0;
}
// End Grabbing thread  

Когда программа получает RTSP H264 видеоданные с разрешением 704x576, тогда декодированные видеоизображения в порядке.При получении RTSP H264 HD-видео данных с разрешением 1280x720 похоже, что первое видеоизображение декодируется нормально, а затем видеоизображения декодируются, но всегда с некоторой ошибкой.

Пожалуйста, помогите мне решить эту проблему!

Вот краткое описание проблемы:
У меня есть модель IP-камеры HI3518E_50H10L_S39 (продукт из Китая).
Камера может передавать видеопоток H264 как с разрешением 704x576 (с RTSP URI "rtsp: //192.168.1.18:554/user=admin_password=tlJwpbo6_channel=1_stream=1.sdp?real_stream ") или 1280x720 (с URI RTSP" rtsp: //192.168.1.18: 554 / user = admin_password = tlJwpbo6_channel = 1? real_stream ").
Используя утилиту FFplay, я могу получить к ним доступ и отобразить их с хорошим качеством изображения.
Для тестирования захвата с этой камеры у меня есть простая (упомянутая выше) программа на VC-2005.В программе «Grabbing thread» используйте FFmpeg библиотеку версии 4.0 для открытия потока RTSP камеры, получения информации о потоке, поиска первого видеопотока ... и подготовки некоторых переменных.
Центром этого потока является цикл: захват кадра (функция av_read_frame) - декодировать, если это видео (функция avcodec_decode_video2) - конвертировать в формат RGB (функция sws_scale) - отображать в окне программы (функция GDI SetDIBitsToDevice).
при запуске программы с камерой RTSPстрим в разрешении 704х576, у меня хорошая видео картинка.Вот пример:
704x576 образец
Когда программа запускается с потоком RTSP камеры с разрешением 1280x720, первое видеоизображение хорошо:
Первое хорошо с разрешением 1280x720
, но тогда не хорошо:
не очень хорошо с разрешением.1280x720
Кажется, что мой вызов функции FFmpeg для avcodec_decode_video2 не может полностью декодировать определенный пакет по некоторым причинам.

...