Михаиллл
МихаилллApril 16, 2020, 2:12 p.m.

Qt и ffmpeg запаздывание отображения картинки.

Добрый день.
С помощью ffmpeg считываю видео, разбиваю на кадры и пытаюсь отобразить картинки на лэйьле.
Почемуто начинает отображатся только последняя картинка и только после завершения работы функции, тогда как предыдущие картинки не отображается, хотя дебаг говорит что функция рисования работает.
Скажите пожалуйста, с чем может быть связан баг отрисовки и как его исправить?

void MainWindow::test2()
{
    static struct SwsContext *img_convert_ctx;
    int videoStream, i, numBytes;
    int ret, got_picture;

    avformat_network_init();   //初始化FFmpeg网络模块
    av_register_all();  //初始化FFMPEG  调用了这个才能正常适用编码器和解码器


    AVFormatContext *pFormatCtx = NULL;
    //Allocate an AVFormatContext.
    pFormatCtx = avformat_alloc_context();

    // Open video file
    if(avformat_open_input(&pFormatCtx, "./Wildlife.wmv", 0, 0) != 0)
        qDebug()<<"Couldn't open file";

    if(avformat_find_stream_info(pFormatCtx, NULL) < 0)
     qDebug()<<"Couldn't find stream information";

    av_dump_format(pFormatCtx, 0, "./Wildlife.wmv", 0);//information abaut file

    AVCodecContext *pCodecCtxOrig = NULL;
    AVCodecContext *pCodecCtx = NULL;

    // 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)
        qDebug()<<"Didn't find a video stream";

    // Get a pointer to the codec context for the video stream
    pCodecCtx=pFormatCtx->streams[videoStream]->codec;

    AVCodec *pCodec = NULL;

    // Find the decoder for the video stream
    pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
    if(pCodec == NULL) {
     fprintf(stderr, "Unsupported codec!\n");
     qDebug()<<"Codec not found";
    }

    // Copy context
    //pCodecCtx = avcodec_alloc_context3(pCodec);
//    if(avcodec_copy_context(pCodecCtx, pCodecCtxOrig) != 0) {  //not work!!!!!!!!!!!!!!!!!!!!!
//     qDebug()<<"Error copying codec context";
//    }
    // Open codec
    AVDictionary *aVDictionary;
    if(avcodec_open2(pCodecCtx, pCodec, NULL) < 0)
        qDebug()<<"Could not open codec";

    // Выделить видеокадр // Allocate video frame
    AVFrame *pFrame = NULL;
    pFrame = av_frame_alloc();

    // Allocate an AVFrame structure
    AVFrame *pFrameRGB;
    pFrameRGB = av_frame_alloc();
    if(pFrameRGB == NULL)
        qDebug()<<"pFrameRGB == NULL";

    uint8_t *buffer = NULL;
    numBytes;
    // Determine required buffer size and allocate buffer
    numBytes=avpicture_get_size(AV_PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height);
    buffer=(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, buffer, AV_PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height);

    struct SwsContext *sws_ctx = NULL;
    int frameFinished;
    AVPacket packet;
    // initialize SWS context for software scaling
    sws_ctx = sws_getContext(pCodecCtx->width,
        pCodecCtx->height,
        pCodecCtx->pix_fmt,
        pCodecCtx->width,
        pCodecCtx->height,
        AV_PIX_FMT_RGB24,
        SWS_BILINEAR,
        NULL,
        NULL,
        NULL
        );

    i=0;
    while(av_read_frame(pFormatCtx, &packet)>=0) {
      // Is this a packet from the video stream?
      if(packet.stream_index==videoStream) {
        // Decode video frame
        avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);

        // Did we get a video frame?
        if(frameFinished) {
        // Convert the image from its native format to RGB
            sws_scale(sws_ctx, (uint8_t const * const *)pFrame->data,
              pFrame->linesize, 0, pCodecCtx->height,
              pFrameRGB->data, pFrameRGB->linesize);

            // view image on label
            //if(++i<=20) //first 20 images view on label
            {
                qDebug()<<"view image on label";
                QImage image( pCodecCtx->width, pCodecCtx->height, QImage::Format_RGB888 );
                for( int y = 0; y < pCodecCtx->height; ++y ){
                   memcpy( image.scanLine(y), pFrameRGB->data[0]+y * pFrameRGB->linesize[0], pCodecCtx->width * 3 );
                }
                //ui->label->setPixmap(QPixmap::fromImage(image,Qt::AutoColor));
                paintImageOnLabel(image);
                qDebug()<<"view image on label222";
            }
        }
      }

      // Free the packet that was allocated by av_read_frame
      av_free_packet(&packet);
    }

    // Free the RGB image
    av_free(buffer);
    av_frame_free(&pFrameRGB);

    // Free the YUV frame
    av_frame_free(&pFrame);

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

    // Close the video file
    avformat_close_input(&pFormatCtx);
}
void MainWindow::paintImageOnLabel(QImage image)
{
    qDebug()<<"paintImageOnLabel()";
    ui->label->update();
    ui->label->setPixmap(QPixmap::fromImage(image,Qt::AutoColor));
    ui->label->update();
    //QThread::sleep(1);
}

Картинка рисуется в этом участке кода

                qDebug()<<"view image on label";
                QImage image( pCodecCtx->width, pCodecCtx->height, QImage::Format_RGB888 );
                for( int y = 0; y < pCodecCtx->height; ++y ){
                   memcpy( image.scanLine(y), pFrameRGB->data[0]+y * pFrameRGB->linesize[0], pCodecCtx->width * 3 );
                }
                //ui->label->setPixmap(QPixmap::fromImage(image,Qt::AutoColor));
                paintImageOnLabel(image);
                qDebug()<<"view image on label222";
We recommend hosting TIMEWEB
We recommend hosting TIMEWEB
Stable hosting, on which the social network EVILEG is located. For projects on Django we recommend VDS hosting.

Do you like it? Share on social networks!

6
Михаиллл
  • April 17, 2020, 4 a.m.

Говорят что это все из-за цикла while, говорят он блокирует петлю событий и потому не рисуется лэйбел. Похоже нужно использовать QTimer. Но не понимаю, как его использовать при чтении. Подскажите пожалуйста.

    Evgenii Legotckoi
    • April 17, 2020, 4:20 a.m.

    Я согласен с тем, что говорят.
    Думаю, что вам нужно в классе MainWindow добавить QTimer на стеке, в конструкторе класса MainWindow подключить к слоту timeout таймера слот, который будет рисовать каждый кадр, то есть по сути либо всё содержимое метода test2 либо необходимую для отрисовки часть.
    Таймер запускать с необходимой частотой, чтобы был там FPS 30 например.

      Михаиллл
      • April 17, 2020, 4:46 a.m.

      Не совсем Вас понял. Т.е. нужно сначало все картинки нужно записать в вектор и уже потом рисовать из этого вектора по таймеру?

        Evgenii Legotckoi
        • April 17, 2020, 4:47 a.m.

        Нет, таймер запускает периодически слот, например 30 раз в секунду, который проверяет наличие новых фреймов, и если фрейм существует то отрисовывает его.
        По идее за одну сработку слота будет отрисовываться один кадр.

          Михаиллл
          • April 17, 2020, 5 a.m.

          А если чтение фалйла будет в раз 5 быстрее? При таком подходе будут воспроизводиться картинки с большим количеством пропусков. Что бы оно работало, нужно задать скорость работы цикла, а это ведь зависит только от процессора. Или я не так вас понял?

            Evgenii Legotckoi
            • April 17, 2020, 5:07 a.m.
            • (edited)
            • The answer was marked as a solution.

            Вы меня правильно поняли.
            Вообще, это вопрос задачи, которую вы пытаетесь реализовать.

            Если вам нужно просто воспроизведение, то проблемы я тут собственно говоря не вижу. Буффер кадров ffmpeg по идее не должен наполняться быстрее, чем воспроизводится видео. А человеческий глаз не воспринимает быстрее 30 кадров в секунду. То есть не должно быть заметно, даже если будут пропуски.

            Если же вы хотите считывать все кадры и не пропускать ничего, то тогда переносите этот код в отдельный поток через QTread::moveToThread и выполняйте цикл while пересылая фреймы в главный поток окна через сигнал-слотовое соединение. Тогда таймер не нужен будет.

              Comments

              Only authorized users can post comments.
              Please, Log in or Sign up
              AD

              C ++ - Test 004. Pointers, Arrays and Loops

              • Result:50points,
              • Rating points-4
              m

              C ++ - Test 004. Pointers, Arrays and Loops

              • Result:80points,
              • Rating points4
              m

              C ++ - Test 004. Pointers, Arrays and Loops

              • Result:20points,
              • Rating points-10
              Last comments
              i
              innorwallNov. 12, 2024, 9:12 a.m.
              Django - Tutorial 055. How to write auto populate field functionality Freckles because of several brand names retin a, atralin buy generic priligy
              i
              innorwallNov. 12, 2024, 5:23 a.m.
              QML - Tutorial 035. Using enumerations in QML without C ++ priligy cvs 24 Together with antibiotics such as amphotericin B 10, griseofulvin 11 and streptomycin 12, chloramphenicol 9 is in the World Health Organisation s List of Essential Medici…
              i
              innorwallNov. 12, 2024, 2:50 a.m.
              Qt/C++ - Lesson 052. Customization Qt Audio player in the style of AIMP It decreases stress, supports hormone balance, and regulates and increases blood flow to the reproductive organs buy priligy online safe Promising data were reported in a PDX model re…
              i
              innorwallNov. 12, 2024, 1:19 a.m.
              Heap sorting algorithm The role of raloxifene in preventing breast cancer priligy precio
              i
              innorwallNov. 12, 2024, 12:55 a.m.
              PyQt5 - Lesson 006. Work with QTableWidget buy priligy 60 mg 53 have been reported by Javanovic Santa et al
              Now discuss on the forum
              i
              innorwallNov. 12, 2024, 7:56 a.m.
              добавить qlineseries в функции buy priligy senior brother Chu He, whom he had known for many years
              i
              innorwallNov. 11, 2024, 9:55 p.m.
              Всё ещё разбираюсь с кешем. priligy walgreens levitra dulcolax carbs The third ring was found to be made up of ultra relativistic electrons, which are also present in both the outer and inner rings
              9
              9AnonimOct. 25, 2024, 7:10 p.m.
              Машина тьюринга // Начальное состояние 0 0, ,<,1 // Переход в состояние 1 при пустом символе 0,0,>,0 // Остаемся в состоянии 0, двигаясь вправо при встрече 0 0,1,>…

              Follow us in social networks