• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * AVPacket functions for libavcodec
3  * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
22 #include <string.h>
23 
24 #include "libavutil/avassert.h"
25 #include "libavutil/intreadwrite.h"
26 #include "libavutil/mathematics.h"
27 #include "libavutil/mem.h"
28 #include "libavutil/rational.h"
29 
30 #include "defs.h"
31 #include "packet.h"
32 #include "packet_internal.h"
33 
34 #if FF_API_INIT_PACKET
av_init_packet(AVPacket * pkt)35 void av_init_packet(AVPacket *pkt)
36 {
37     pkt->pts                  = AV_NOPTS_VALUE;
38     pkt->dts                  = AV_NOPTS_VALUE;
39     pkt->pos                  = -1;
40     pkt->duration             = 0;
41     pkt->flags                = 0;
42     pkt->stream_index         = 0;
43     pkt->buf                  = NULL;
44     pkt->side_data            = NULL;
45     pkt->side_data_elems      = 0;
46     pkt->opaque               = NULL;
47     pkt->opaque_ref           = NULL;
48     pkt->time_base            = av_make_q(0, 1);
49 }
50 #endif
51 
get_packet_defaults(AVPacket * pkt)52 static void get_packet_defaults(AVPacket *pkt)
53 {
54     memset(pkt, 0, sizeof(*pkt));
55 
56     pkt->pts             = AV_NOPTS_VALUE;
57     pkt->dts             = AV_NOPTS_VALUE;
58     pkt->pos             = -1;
59     pkt->time_base       = av_make_q(0, 1);
60 }
61 
av_packet_alloc(void)62 AVPacket *av_packet_alloc(void)
63 {
64     AVPacket *pkt = av_malloc(sizeof(AVPacket));
65     if (!pkt)
66         return pkt;
67 
68     get_packet_defaults(pkt);
69 
70     return pkt;
71 }
72 
av_packet_free(AVPacket ** pkt)73 void av_packet_free(AVPacket **pkt)
74 {
75     if (!pkt || !*pkt)
76         return;
77 
78     av_packet_unref(*pkt);
79     av_freep(pkt);
80 }
81 
packet_alloc(AVBufferRef ** buf,int size)82 static int packet_alloc(AVBufferRef **buf, int size)
83 {
84     int ret;
85     if (size < 0 || size >= INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE)
86         return AVERROR(EINVAL);
87 
88     ret = av_buffer_realloc(buf, size + AV_INPUT_BUFFER_PADDING_SIZE);
89     if (ret < 0)
90         return ret;
91 
92     memset((*buf)->data + size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
93 
94     return 0;
95 }
96 
av_new_packet(AVPacket * pkt,int size)97 int av_new_packet(AVPacket *pkt, int size)
98 {
99     AVBufferRef *buf = NULL;
100     int ret = packet_alloc(&buf, size);
101     if (ret < 0)
102         return ret;
103 
104     get_packet_defaults(pkt);
105     pkt->buf      = buf;
106     pkt->data     = buf->data;
107     pkt->size     = size;
108 
109     return 0;
110 }
111 
av_shrink_packet(AVPacket * pkt,int size)112 void av_shrink_packet(AVPacket *pkt, int size)
113 {
114     if (pkt->size <= size)
115         return;
116     pkt->size = size;
117     memset(pkt->data + size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
118 }
119 
av_grow_packet(AVPacket * pkt,int grow_by)120 int av_grow_packet(AVPacket *pkt, int grow_by)
121 {
122     int new_size;
123     av_assert0((unsigned)pkt->size <= INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE);
124     if ((unsigned)grow_by >
125         INT_MAX - (pkt->size + AV_INPUT_BUFFER_PADDING_SIZE))
126         return AVERROR(ENOMEM);
127 
128     new_size = pkt->size + grow_by + AV_INPUT_BUFFER_PADDING_SIZE;
129     if (pkt->buf) {
130         size_t data_offset;
131         uint8_t *old_data = pkt->data;
132         if (pkt->data == NULL) {
133             data_offset = 0;
134             pkt->data = pkt->buf->data;
135         } else {
136             data_offset = pkt->data - pkt->buf->data;
137             if (data_offset > INT_MAX - new_size)
138                 return AVERROR(ENOMEM);
139         }
140 
141         if (new_size + data_offset > pkt->buf->size ||
142             !av_buffer_is_writable(pkt->buf)) {
143             int ret;
144 
145             // allocate slightly more than requested to avoid excessive
146             // reallocations
147             if (new_size + data_offset < INT_MAX - new_size/16)
148                 new_size += new_size/16;
149 
150             ret = av_buffer_realloc(&pkt->buf, new_size + data_offset);
151             if (ret < 0) {
152                 pkt->data = old_data;
153                 return ret;
154             }
155             pkt->data = pkt->buf->data + data_offset;
156         }
157     } else {
158         pkt->buf = av_buffer_alloc(new_size);
159         if (!pkt->buf)
160             return AVERROR(ENOMEM);
161         if (pkt->size > 0)
162             memcpy(pkt->buf->data, pkt->data, pkt->size);
163         pkt->data = pkt->buf->data;
164     }
165     pkt->size += grow_by;
166     memset(pkt->data + pkt->size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
167 
168     return 0;
169 }
170 
av_packet_from_data(AVPacket * pkt,uint8_t * data,int size)171 int av_packet_from_data(AVPacket *pkt, uint8_t *data, int size)
172 {
173     if (size >= INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE)
174         return AVERROR(EINVAL);
175 
176     pkt->buf = av_buffer_create(data, size + AV_INPUT_BUFFER_PADDING_SIZE,
177                                 av_buffer_default_free, NULL, 0);
178     if (!pkt->buf)
179         return AVERROR(ENOMEM);
180 
181     pkt->data = data;
182     pkt->size = size;
183 
184     return 0;
185 }
186 
av_packet_free_side_data(AVPacket * pkt)187 void av_packet_free_side_data(AVPacket *pkt)
188 {
189     int i;
190     for (i = 0; i < pkt->side_data_elems; i++)
191         av_freep(&pkt->side_data[i].data);
192     av_freep(&pkt->side_data);
193     pkt->side_data_elems = 0;
194 }
195 
av_packet_add_side_data(AVPacket * pkt,enum AVPacketSideDataType type,uint8_t * data,size_t size)196 int av_packet_add_side_data(AVPacket *pkt, enum AVPacketSideDataType type,
197                             uint8_t *data, size_t size)
198 {
199     AVPacketSideData *tmp;
200     int i, elems = pkt->side_data_elems;
201 
202     for (i = 0; i < elems; i++) {
203         AVPacketSideData *sd = &pkt->side_data[i];
204 
205         if (sd->type == type) {
206             av_free(sd->data);
207             sd->data = data;
208             sd->size = size;
209             return 0;
210         }
211     }
212 
213     if ((unsigned)elems + 1 > AV_PKT_DATA_NB)
214         return AVERROR(ERANGE);
215 
216     tmp = av_realloc(pkt->side_data, (elems + 1) * sizeof(*tmp));
217     if (!tmp)
218         return AVERROR(ENOMEM);
219 
220     pkt->side_data = tmp;
221     pkt->side_data[elems].data = data;
222     pkt->side_data[elems].size = size;
223     pkt->side_data[elems].type = type;
224     pkt->side_data_elems++;
225 
226     return 0;
227 }
228 
229 
av_packet_new_side_data(AVPacket * pkt,enum AVPacketSideDataType type,size_t size)230 uint8_t *av_packet_new_side_data(AVPacket *pkt, enum AVPacketSideDataType type,
231                                  size_t size)
232 {
233     int ret;
234     uint8_t *data;
235 
236     if (size > SIZE_MAX - AV_INPUT_BUFFER_PADDING_SIZE)
237         return NULL;
238     data = av_mallocz(size + AV_INPUT_BUFFER_PADDING_SIZE);
239     if (!data)
240         return NULL;
241 
242     ret = av_packet_add_side_data(pkt, type, data, size);
243     if (ret < 0) {
244         av_freep(&data);
245         return NULL;
246     }
247 
248     return data;
249 }
250 
av_packet_get_side_data(const AVPacket * pkt,enum AVPacketSideDataType type,size_t * size)251 uint8_t *av_packet_get_side_data(const AVPacket *pkt, enum AVPacketSideDataType type,
252                                  size_t *size)
253 {
254     int i;
255 
256     for (i = 0; i < pkt->side_data_elems; i++) {
257         if (pkt->side_data[i].type == type) {
258             if (size)
259                 *size = pkt->side_data[i].size;
260             return pkt->side_data[i].data;
261         }
262     }
263     if (size)
264         *size = 0;
265     return NULL;
266 }
267 
av_packet_side_data_name(enum AVPacketSideDataType type)268 const char *av_packet_side_data_name(enum AVPacketSideDataType type)
269 {
270     switch(type) {
271     case AV_PKT_DATA_PALETTE:                    return "Palette";
272     case AV_PKT_DATA_NEW_EXTRADATA:              return "New Extradata";
273     case AV_PKT_DATA_PARAM_CHANGE:               return "Param Change";
274     case AV_PKT_DATA_H263_MB_INFO:               return "H263 MB Info";
275     case AV_PKT_DATA_REPLAYGAIN:                 return "Replay Gain";
276     case AV_PKT_DATA_DISPLAYMATRIX:              return "Display Matrix";
277     case AV_PKT_DATA_STEREO3D:                   return "Stereo 3D";
278     case AV_PKT_DATA_AUDIO_SERVICE_TYPE:         return "Audio Service Type";
279     case AV_PKT_DATA_QUALITY_STATS:              return "Quality stats";
280     case AV_PKT_DATA_FALLBACK_TRACK:             return "Fallback track";
281     case AV_PKT_DATA_CPB_PROPERTIES:             return "CPB properties";
282     case AV_PKT_DATA_SKIP_SAMPLES:               return "Skip Samples";
283     case AV_PKT_DATA_JP_DUALMONO:                return "JP Dual Mono";
284     case AV_PKT_DATA_STRINGS_METADATA:           return "Strings Metadata";
285     case AV_PKT_DATA_SUBTITLE_POSITION:          return "Subtitle Position";
286     case AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL:   return "Matroska BlockAdditional";
287     case AV_PKT_DATA_WEBVTT_IDENTIFIER:          return "WebVTT ID";
288     case AV_PKT_DATA_WEBVTT_SETTINGS:            return "WebVTT Settings";
289     case AV_PKT_DATA_METADATA_UPDATE:            return "Metadata Update";
290     case AV_PKT_DATA_MPEGTS_STREAM_ID:           return "MPEGTS Stream ID";
291     case AV_PKT_DATA_MASTERING_DISPLAY_METADATA: return "Mastering display metadata";
292     case AV_PKT_DATA_CONTENT_LIGHT_LEVEL:        return "Content light level metadata";
293     case AV_PKT_DATA_SPHERICAL:                  return "Spherical Mapping";
294     case AV_PKT_DATA_A53_CC:                     return "A53 Closed Captions";
295     case AV_PKT_DATA_ENCRYPTION_INIT_INFO:       return "Encryption initialization data";
296     case AV_PKT_DATA_ENCRYPTION_INFO:            return "Encryption info";
297     case AV_PKT_DATA_AFD:                        return "Active Format Description data";
298     case AV_PKT_DATA_PRFT:                       return "Producer Reference Time";
299     case AV_PKT_DATA_ICC_PROFILE:                return "ICC Profile";
300     case AV_PKT_DATA_DOVI_CONF:                  return "DOVI configuration record";
301     case AV_PKT_DATA_S12M_TIMECODE:              return "SMPTE ST 12-1:2014 timecode";
302     case AV_PKT_DATA_DYNAMIC_HDR10_PLUS:         return "HDR10+ Dynamic Metadata (SMPTE 2094-40)";
303     }
304     return NULL;
305 }
306 
av_packet_pack_dictionary(AVDictionary * dict,size_t * size)307 uint8_t *av_packet_pack_dictionary(AVDictionary *dict, size_t *size)
308 {
309     uint8_t *data = NULL;
310     *size = 0;
311 
312     if (!dict)
313         return NULL;
314 
315     for (int pass = 0; pass < 2; pass++) {
316         const AVDictionaryEntry *t = NULL;
317         size_t total_length = 0;
318 
319         while ((t = av_dict_get(dict, "", t, AV_DICT_IGNORE_SUFFIX))) {
320             for (int i = 0; i < 2; i++) {
321                 const char  *str = i ? t->value : t->key;
322                 const size_t len = strlen(str) + 1;
323 
324                 if (pass)
325                     memcpy(data + total_length, str, len);
326                 else if (len > SIZE_MAX - total_length)
327                     return NULL;
328                 total_length += len;
329             }
330         }
331         if (pass)
332             break;
333         data = av_malloc(total_length);
334         if (!data)
335             return NULL;
336         *size = total_length;
337     }
338 
339     return data;
340 }
341 
av_packet_unpack_dictionary(const uint8_t * data,size_t size,AVDictionary ** dict)342 int av_packet_unpack_dictionary(const uint8_t *data, size_t size,
343                                 AVDictionary **dict)
344 {
345     const uint8_t *end;
346     int ret;
347 
348     if (!dict || !data || !size)
349         return 0;
350     end = data + size;
351     if (size && end[-1])
352         return AVERROR_INVALIDDATA;
353     while (data < end) {
354         const uint8_t *key = data;
355         const uint8_t *val = data + strlen(key) + 1;
356 
357         if (val >= end || !*key)
358             return AVERROR_INVALIDDATA;
359 
360         ret = av_dict_set(dict, key, val, 0);
361         if (ret < 0)
362             return ret;
363         data = val + strlen(val) + 1;
364     }
365 
366     return 0;
367 }
368 
av_packet_shrink_side_data(AVPacket * pkt,enum AVPacketSideDataType type,size_t size)369 int av_packet_shrink_side_data(AVPacket *pkt, enum AVPacketSideDataType type,
370                                size_t size)
371 {
372     int i;
373 
374     for (i = 0; i < pkt->side_data_elems; i++) {
375         if (pkt->side_data[i].type == type) {
376             if (size > pkt->side_data[i].size)
377                 return AVERROR(ENOMEM);
378             pkt->side_data[i].size = size;
379             return 0;
380         }
381     }
382     return AVERROR(ENOENT);
383 }
384 
av_packet_copy_props(AVPacket * dst,const AVPacket * src)385 int av_packet_copy_props(AVPacket *dst, const AVPacket *src)
386 {
387     int i, ret;
388 
389     dst->pts                  = src->pts;
390     dst->dts                  = src->dts;
391     dst->pos                  = src->pos;
392     dst->duration             = src->duration;
393     dst->flags                = src->flags;
394     dst->stream_index         = src->stream_index;
395     dst->opaque               = src->opaque;
396     dst->time_base            = src->time_base;
397     dst->opaque_ref           = NULL;
398     dst->side_data            = NULL;
399     dst->side_data_elems      = 0;
400 
401     ret = av_buffer_replace(&dst->opaque_ref, src->opaque_ref);
402     if (ret < 0)
403         return ret;
404 
405     for (i = 0; i < src->side_data_elems; i++) {
406         enum AVPacketSideDataType type = src->side_data[i].type;
407         size_t size = src->side_data[i].size;
408         uint8_t *src_data = src->side_data[i].data;
409         uint8_t *dst_data = av_packet_new_side_data(dst, type, size);
410 
411         if (!dst_data) {
412             av_buffer_unref(&dst->opaque_ref);
413             av_packet_free_side_data(dst);
414             return AVERROR(ENOMEM);
415         }
416         memcpy(dst_data, src_data, size);
417     }
418 
419     return 0;
420 }
421 
av_packet_unref(AVPacket * pkt)422 void av_packet_unref(AVPacket *pkt)
423 {
424     av_packet_free_side_data(pkt);
425     av_buffer_unref(&pkt->opaque_ref);
426     av_buffer_unref(&pkt->buf);
427     get_packet_defaults(pkt);
428 }
429 
av_packet_ref(AVPacket * dst,const AVPacket * src)430 int av_packet_ref(AVPacket *dst, const AVPacket *src)
431 {
432     int ret;
433 
434     dst->buf = NULL;
435 
436     ret = av_packet_copy_props(dst, src);
437     if (ret < 0)
438         goto fail;
439 
440     if (!src->buf) {
441         ret = packet_alloc(&dst->buf, src->size);
442         if (ret < 0)
443             goto fail;
444         av_assert1(!src->size || src->data);
445         if (src->size)
446             memcpy(dst->buf->data, src->data, src->size);
447 
448         dst->data = dst->buf->data;
449     } else {
450         dst->buf = av_buffer_ref(src->buf);
451         if (!dst->buf) {
452             ret = AVERROR(ENOMEM);
453             goto fail;
454         }
455         dst->data = src->data;
456     }
457 
458     dst->size = src->size;
459 
460     return 0;
461 fail:
462     av_packet_unref(dst);
463     return ret;
464 }
465 
av_packet_clone(const AVPacket * src)466 AVPacket *av_packet_clone(const AVPacket *src)
467 {
468     AVPacket *ret = av_packet_alloc();
469 
470     if (!ret)
471         return ret;
472 
473     if (av_packet_ref(ret, src))
474         av_packet_free(&ret);
475 
476     return ret;
477 }
478 
av_packet_move_ref(AVPacket * dst,AVPacket * src)479 void av_packet_move_ref(AVPacket *dst, AVPacket *src)
480 {
481     *dst = *src;
482     get_packet_defaults(src);
483 }
484 
av_packet_make_refcounted(AVPacket * pkt)485 int av_packet_make_refcounted(AVPacket *pkt)
486 {
487     int ret;
488 
489     if (pkt->buf)
490         return 0;
491 
492     ret = packet_alloc(&pkt->buf, pkt->size);
493     if (ret < 0)
494         return ret;
495     av_assert1(!pkt->size || pkt->data);
496     if (pkt->size)
497         memcpy(pkt->buf->data, pkt->data, pkt->size);
498 
499     pkt->data = pkt->buf->data;
500 
501     return 0;
502 }
503 
av_packet_make_writable(AVPacket * pkt)504 int av_packet_make_writable(AVPacket *pkt)
505 {
506     AVBufferRef *buf = NULL;
507     int ret;
508 
509     if (pkt->buf && av_buffer_is_writable(pkt->buf))
510         return 0;
511 
512     ret = packet_alloc(&buf, pkt->size);
513     if (ret < 0)
514         return ret;
515     av_assert1(!pkt->size || pkt->data);
516     if (pkt->size)
517         memcpy(buf->data, pkt->data, pkt->size);
518 
519     av_buffer_unref(&pkt->buf);
520     pkt->buf  = buf;
521     pkt->data = buf->data;
522 
523     return 0;
524 }
525 
av_packet_rescale_ts(AVPacket * pkt,AVRational src_tb,AVRational dst_tb)526 void av_packet_rescale_ts(AVPacket *pkt, AVRational src_tb, AVRational dst_tb)
527 {
528     if (pkt->pts != AV_NOPTS_VALUE)
529         pkt->pts = av_rescale_q(pkt->pts, src_tb, dst_tb);
530     if (pkt->dts != AV_NOPTS_VALUE)
531         pkt->dts = av_rescale_q(pkt->dts, src_tb, dst_tb);
532     if (pkt->duration > 0)
533         pkt->duration = av_rescale_q(pkt->duration, src_tb, dst_tb);
534 }
535 
avpriv_packet_list_put(PacketList * packet_buffer,AVPacket * pkt,int (* copy)(AVPacket * dst,const AVPacket * src),int flags)536 int avpriv_packet_list_put(PacketList *packet_buffer,
537                            AVPacket      *pkt,
538                            int (*copy)(AVPacket *dst, const AVPacket *src),
539                            int flags)
540 {
541     PacketListEntry *pktl = av_malloc(sizeof(*pktl));
542     int ret;
543 
544     if (!pktl)
545         return AVERROR(ENOMEM);
546 
547     if (copy) {
548         get_packet_defaults(&pktl->pkt);
549         ret = copy(&pktl->pkt, pkt);
550         if (ret < 0) {
551             av_free(pktl);
552             return ret;
553         }
554     } else {
555         ret = av_packet_make_refcounted(pkt);
556         if (ret < 0) {
557             av_free(pktl);
558             return ret;
559         }
560         av_packet_move_ref(&pktl->pkt, pkt);
561     }
562 
563     pktl->next = NULL;
564 
565     if (packet_buffer->head)
566         packet_buffer->tail->next = pktl;
567     else
568         packet_buffer->head = pktl;
569 
570     /* Add the packet in the buffered packet list. */
571     packet_buffer->tail = pktl;
572     return 0;
573 }
574 
avpriv_packet_list_get(PacketList * pkt_buffer,AVPacket * pkt)575 int avpriv_packet_list_get(PacketList *pkt_buffer,
576                            AVPacket      *pkt)
577 {
578     PacketListEntry *pktl = pkt_buffer->head;
579     if (!pktl)
580         return AVERROR(EAGAIN);
581     *pkt        = pktl->pkt;
582     pkt_buffer->head = pktl->next;
583     if (!pkt_buffer->head)
584         pkt_buffer->tail = NULL;
585     av_freep(&pktl);
586     return 0;
587 }
588 
avpriv_packet_list_free(PacketList * pkt_buf)589 void avpriv_packet_list_free(PacketList *pkt_buf)
590 {
591     PacketListEntry *tmp = pkt_buf->head;
592 
593     while (tmp) {
594         PacketListEntry *pktl = tmp;
595         tmp = pktl->next;
596         av_packet_unref(&pktl->pkt);
597         av_freep(&pktl);
598     }
599     pkt_buf->head = pkt_buf->tail = NULL;
600 }
601 
ff_side_data_set_encoder_stats(AVPacket * pkt,int quality,int64_t * error,int error_count,int pict_type)602 int ff_side_data_set_encoder_stats(AVPacket *pkt, int quality, int64_t *error, int error_count, int pict_type)
603 {
604     uint8_t *side_data;
605     size_t side_data_size;
606     int i;
607 
608     side_data = av_packet_get_side_data(pkt, AV_PKT_DATA_QUALITY_STATS, &side_data_size);
609     if (!side_data) {
610         side_data_size = 4+4+8*error_count;
611         side_data = av_packet_new_side_data(pkt, AV_PKT_DATA_QUALITY_STATS,
612                                             side_data_size);
613     }
614 
615     if (!side_data || side_data_size < 4+4+8*error_count)
616         return AVERROR(ENOMEM);
617 
618     AV_WL32(side_data   , quality  );
619     side_data[4] = pict_type;
620     side_data[5] = error_count;
621     for (i = 0; i<error_count; i++)
622         AV_WL64(side_data+8 + 8*i , error[i]);
623 
624     return 0;
625 }
626 
ff_side_data_set_prft(AVPacket * pkt,int64_t timestamp)627 int ff_side_data_set_prft(AVPacket *pkt, int64_t timestamp)
628 {
629     AVProducerReferenceTime *prft;
630     uint8_t *side_data;
631     size_t side_data_size;
632 
633     side_data = av_packet_get_side_data(pkt, AV_PKT_DATA_PRFT, &side_data_size);
634     if (!side_data) {
635         side_data_size = sizeof(AVProducerReferenceTime);
636         side_data = av_packet_new_side_data(pkt, AV_PKT_DATA_PRFT, side_data_size);
637     }
638 
639     if (!side_data || side_data_size < sizeof(AVProducerReferenceTime))
640         return AVERROR(ENOMEM);
641 
642     prft = (AVProducerReferenceTime *)side_data;
643     prft->wallclock = timestamp;
644     prft->flags = 0;
645 
646     return 0;
647 }
648