/
VideoThread.cpp
173 lines (130 loc) · 4.67 KB
/
VideoThread.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
#include "VideoThread.h"
//COSTRUTTORE
VideoThread::VideoThread(QObject *parent): QThread(parent)
{
pts = 0;
packet = &pkt1;
_is = NULL;
}
void VideoThread::run(){
/* alloco i frame YVU e RGB */
pFrame = avcodec_alloc_frame();
pFrameRGB = avcodec_alloc_frame();
/* da questo momento in poi permetto alla finestra di resfreshare */
_is->window->startdisplay();
//Calculate the size in bytes that a picture of the given width and height would occupy if stored in the given picture format.
bytes = avpicture_get_size(CONV_FORMAT, _is->video_st->codec->width, _is->video_st->codec->height);
uint8_t *video_buffer = (uint8_t*)av_malloc( bytes * sizeof(uint8_t) );
avpicture_fill((AVPicture *)pFrameRGB, video_buffer, CONV_FORMAT, _is->video_st->codec->width, _is->video_st->codec->height);
/*
ciclo di lettura dei frame
prelevo dalla coda dei pkt
decodifico il frame YUV
trasformo il frame in RGB
aggiungo il frameRGB alla nuova coda
*/
while(1) {
if(_is->ut.getPauseValue() && !_is->ut.getStopValue()){
continue;
//this->usleep(10000);
};
// leggo i paccehtti dalla coda
if(_is->videoq.Get(packet, 1) < 0){
// means we quit getting packets
//qDebug() << "quitting getting packets - videothread";
break;
}
//controllo se ho letto pacchetto di FLUSH
if(packet->data == _is->flush_pkt->data){
//qDebug() << "VideoThread - letto FLUSH PKT";
avcodec_flush_buffers(_is->video_st->codec);
_is->pictq.Flush();
_is->frame_last_pts = AV_NOPTS_VALUE;
_is->frame_last_delay = 0;
_is->frame_timer = (double)av_gettime() / 1000000.0;
continue;
}
pts = 0; //resetto il pts a 0, ovvero non trovato
//Save global pts to be stored in pFrame in first call
_is->global_video_pkt_pts = packet->pts;
// Decode video frame
avcodec_decode_video2(_is->video_st->codec, pFrame, &frameFinished, packet);
//nota: opaque è una variabile interna a pFrame lasciata libera
//per essere usata dall'utente come variabile di appoggio per dei dati
/* caso in cui NON RIESCO a reperire DTS, ma sho allocato il buffer */
if (packet->dts == (int64_t)AV_NOPTS_VALUE && pFrame->opaque && *(uint64_t*)pFrame->opaque != AV_NOPTS_VALUE)
{
//vado a reperire il PTS del primo pacchetto, messo in opaque dalla nostra funzione
//di allocazione del buffer
pts = *(uint64_t *) pFrame->opaque;
}
/* caso in cui RIESCO a reperire DTS */
else if (packet->dts != (int64_t)AV_NOPTS_VALUE)
{
pts = packet->dts;
}
else
{
pts = 0;
}
/**
PTS = PTS * (time_base convertito in double)
ottengo cosi il PTS in secondi
*/
pts *= av_q2d(_is->video_st->time_base);
// Did we get a video frame?
if(frameFinished) {
synchronize_video(); //sincronizzazione del PTS
/* conversione pFrame -> pFrameRGB */
sws_scale(_is->sws_ctx, (uint8_t const * const *)pFrame->data,
pFrame->linesize, 0, _is->video_st->codec->height, pFrameRGB->data,
pFrameRGB->linesize);
while(_is->pictq.getSize() > VIDEO_PICTURE_QUEUE_SIZE && (_is->ut.getStopValue() == false)){
this->usleep(1000);
}
/* aggiunta del frame RGB alla nuova coda */
if(_is->pictq.Put(pFrameRGB, pts) < 0) {
//qDebug() << "quitting putting frame - videothread";
break;
}
}
av_free_packet(packet);
}
av_free(pFrame);
av_free(pFrameRGB);
return;
}
////////////////////////////////////////////////////////////////////////////////////////////
void VideoThread::SetVideoState(VideoState *is){
_is = is;
};
////////////////////////////////////////////////////////////////////////////////////////////
/**
funzione che aggiorna i PTS in modo tale che siano sincronizzati con tutto
devo quindi occuparsi di 2 problemi:
1) la ripetizione di uno stesso frame
2) sincronizzazione del video all'audio
per fare cio sfrutto video_clock che mantiene traccia tra quanto aspetto il prossimo frame
*/
void VideoThread::synchronize_video()
{
double frame_delay; //ritardo del frame
if (pts != 0)
{
/* if we have pts, set video clock to it */
_is->video_clock = pts;
}
else
{
/* if we aren't given a pts, set it to the clock */
pts = _is->video_clock;
}
//faccio questi 2 passaggi per ottenere il frame_delay in double
/* update the video clock */
frame_delay = av_q2d(_is->video_st->codec->time_base);
/* if we are repeating a frame, adjust clock accordingly */
frame_delay += pFrame->repeat_pict * (frame_delay * 0.5);
//vado cosi ad aggiornare il video_clock
_is->video_clock += frame_delay;
}
////////////////////////////////////////////////////////////////////////////////////////////