Михаиллл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
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!
AD
- Akiv Doros
- Nov. 12, 2024, 1:58 a.m.
C ++ - Test 004. Pointers, Arrays and Loops
- Result:50points,
- Rating points-4
m
- molni99
- Oct. 26, 2024, 11:37 a.m.
C ++ - Test 004. Pointers, Arrays and Loops
- Result:80points,
- Rating points4
m
- molni99
- Oct. 26, 2024, 11:29 a.m.
C ++ - Test 004. Pointers, Arrays and Loops
- Result:20points,
- Rating points-10
Last comments
Django - Tutorial 055. How to write auto populate field functionality Freckles because of several brand names retin a, atralin buy generic priligy
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…
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…
Heap sorting algorithm The role of raloxifene in preventing breast cancer priligy precio
PyQt5 - Lesson 006. Work with QTableWidget buy priligy 60 mg 53 have been reported by Javanovic Santa et al
Now discuss on the forum
добавить qlineseries в функции buy priligy senior brother Chu He, whom he had known for many years
Всё ещё разбираюсь с кешем. 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
IscanderCheNov. 1, 2024, 1:43 a.m.
Машина тьюринга // Начальное состояние 0 0, ,<,1 // Переход в состояние 1 при пустом символе 0,0,>,0 // Остаемся в состоянии 0, двигаясь вправо при встрече 0 0,1,>…
ИМ
Реализация навигации по разделам Спасибо Евгений!
Игорь МаксимовOct. 3, 2024, 2:05 p.m.
Говорят что это все из-за цикла while, говорят он блокирует петлю событий и потому не рисуется лэйбел. Похоже нужно использовать QTimer. Но не понимаю, как его использовать при чтении. Подскажите пожалуйста.
Я согласен с тем, что говорят.
Думаю, что вам нужно в классе MainWindow добавить QTimer на стеке, в конструкторе класса MainWindow подключить к слоту timeout таймера слот, который будет рисовать каждый кадр, то есть по сути либо всё содержимое метода test2 либо необходимую для отрисовки часть.
Таймер запускать с необходимой частотой, чтобы был там FPS 30 например.
Не совсем Вас понял. Т.е. нужно сначало все картинки нужно записать в вектор и уже потом рисовать из этого вектора по таймеру?
Нет, таймер запускает периодически слот, например 30 раз в секунду, который проверяет наличие новых фреймов, и если фрейм существует то отрисовывает его.
По идее за одну сработку слота будет отрисовываться один кадр.
А если чтение фалйла будет в раз 5 быстрее? При таком подходе будут воспроизводиться картинки с большим количеством пропусков. Что бы оно работало, нужно задать скорость работы цикла, а это ведь зависит только от процессора. Или я не так вас понял?
Вы меня правильно поняли.
Вообще, это вопрос задачи, которую вы пытаетесь реализовать.
Если вам нужно просто воспроизведение, то проблемы я тут собственно говоря не вижу. Буффер кадров ffmpeg по идее не должен наполняться быстрее, чем воспроизводится видео. А человеческий глаз не воспринимает быстрее 30 кадров в секунду. То есть не должно быть заметно, даже если будут пропуски.
Если же вы хотите считывать все кадры и не пропускать ничего, то тогда переносите этот код в отдельный поток через QTread::moveToThread и выполняйте цикл while пересылая фреймы в главный поток окна через сигнал-слотовое соединение. Тогда таймер не нужен будет.