Source réimprimée: https://www.cnblogs.com/leisure_chn/p/10584910.html
1. Cadre I / Cadre P / Cadre B
I frame : l' image intra-codée (image intra-codée, souvent appelée image clé) contient une image complète des informations d'image, appartient à l'image intra-codée, ne contient pas de vecteurs de mouvement et n'a pas besoin de se référer à d'autres cadrer les images lors du décodage. Par conséquent, le canal peut être commuté au niveau de l'image I-frame sans provoquer de perte d'image ou d'échec du décodage. L'image du cadre I est utilisée pour empêcher l'accumulation et la propagation des erreurs. Dans un GOP fermé, la première trame de chaque GOP doit être une trame I, et les données du GOP actuel ne feront pas référence aux données des GOP précédents et suivants.
Trame P : une trame P (image codée prédictive, image codée prédictive) est une trame codée inter-trame, et la trame I précédente ou la trame P précédente est utilisée pour le codage prédictif.
Trame B : Une trame B (image bidirectionnelle prédite, trame d'image codée bidirectionnelle prédite) est une trame codée inter-trame, qui utilise la trame I ou la trame P avant et (ou) après elle pour le codage prédictif bidirectionnel. Les cadres B ne peuvent pas être utilisés comme cadres de référence.
Les images B ont un taux de compression plus élevé, mais nécessitent plus de temps de mise en mémoire tampon et une utilisation du processeur plus élevée. Par conséquent, les images B conviennent au stockage local et à la vidéo à la demande, mais ne conviennent pas aux systèmes de diffusion en direct qui nécessitent un temps réel élevé. performance.
2. DTS et PTS
DTS (Decoding Time Stamp) indique le temps de décodage de la trame compressée.
PTS (Presentation Time Stamp) indique la durée d'affichage de l'image d'origine obtenue après le décodage de l'image compressée.
DTS et PTS en audio sont les mêmes. Étant donné que les images B dans la vidéo nécessitent une prédiction bidirectionnelle et que les images B dépendent des images avant et après elles, l'ordre de décodage des vidéos contenant des images B est différent de l'ordre d'affichage, c'est-à-dire que DTS et PTS sont différents. Bien sûr, pour les vidéos sans cadres B, le DTS et le PTS sont les mêmes. La figure suivante utilise un diagramme GOP ouvert comme exemple pour illustrer l'ordre de décodage et l'ordre d'affichage du flux
vidéo.L'ordre d'acquisition fait référence à l' ordre dans lequel le capteur d'image acquiert le signal d'origine pour obtenir la trame d'image.
L'ordre de codage fait référence à l'ordre des images après le codage par le codeur. L'ordre des images dans le fichier vidéo local stocké sur le disque est le même que l'ordre de codage.
La séquence de transmission fait référence à la séquence de trames d'images lors de la transmission du flux codé sur le réseau.
L'ordre de décodage fait référence à l' ordre dans lequel le décodeur décode les trames d'image.
L'ordre d'affichage fait référence à l' ordre dans lequel les cadres d'image sont affichés sur le moniteur.
La séquence d'acquisition est la même que la séquence d'affichage. L'ordre de codage, l'ordre de transmission et l'ordre de décodage sont les mêmes.
Prenons comme exemple le cadre "B [1]" de la figure. Lors du décodage de l'image "B [1]", vous devez vous référer au cadre "I [0]" et au cadre "P [3]", donc la trame "P [3]" Elle doit être décodée avant la trame "B [1]". Cela conduit à une incohérence entre l'ordre de décodage et l'ordre d'affichage, et les trames affichées ultérieurement doivent d'abord être décodées.
3. Base de temps et horodatage dans FFmpeg
3.1 Le concept de base de temps et d'horodatage
Dans FFmpeg, la base de temps (time_base) est l'unité d'horodatage et la valeur d'horodatage est multipliée par la base de temps pour obtenir la valeur de temps réelle (en secondes, etc.). Par exemple, si le dts d'une image vidéo est de 40, pts est de 160 et sa base de temps est de 1/1000 seconde, alors il peut être calculé que le temps de décodage de cette image vidéo est de 40 millisecondes (40/1000), et le la durée d'affichage est de 160 millisecondes (160/1 000). Le type d'horodatage (pts / dts) dans FFmpeg est de type int64_t. Lorsqu'une base de temps est considérée comme une impulsion d'horloge, dts / pts peut être considéré comme un nombre d'impulsions d'horloge.
3.2 Trois bases de temps tbr, tbn et tbc
Différents formats d'emballage ont des bases de temps différentes. Différentes bases de temps seront également utilisées à différentes étapes du processus de traitement de l'audio et de la vidéo par FFmpeg.
Il y a trois bases de temps dans FFmepg Les valeurs imprimées de tbr, tbn et tbc dans la ligne de commande sont l'inverse de ces trois bases de temps:
tbn: correspond à la base de temps dans le conteneur. La valeur est la tbc réciproque de AVStream.time_base
: correspondant à la base de temps dans le codec. La valeur est l'inverse de AVCodecContext.time_base tbr
: deviné à partir du flux vidéo, il peut s'agir de la fréquence d'images ou de la fréquence d'images (2 fois la fréquence d'images)
Téléchargement du fichier de test (clic droit et enregistrer sous): tnmil3.flv
utilise ffprobe pour détecter le format de fichier multimédia, comme suit:
think@opensuse> ffprobe tnmil3.flv
ffprobe version 4.1 Copyright (c) 2007-2018 the FFmpeg developers
Input #0, flv, from 'tnmil3.flv':
Metadata:
encoder : Lavf58.20.100
Duration: 00:00:03.60, start: 0.017000, bitrate: 513 kb/s
Stream #0:0: Video: h264 (High), yuv420p(progressive), 784x480, 25 fps, 25 tbr, 1k tbn, 50 tbc
Stream #0:1: Audio: aac (LC), 44100 Hz, stereo, fltp, 128 kb/s
À propos de tbr, tbn et tbc, le texte original est le suivant, à partir de la liste de diffusion FFmpeg:
Il existe trois bases de temps différentes pour les horodatages dans FFmpeg. Les
valeurs imprimées sont en fait les inverses de celles-ci, c'est-à-dire 1 / tbr, 1 / tbn et
1 / tbc.
tbn est la base de temps dans AVStream qui provient du conteneur, je
pense. Il est utilisé pour tous les horodatages AVStream.
tbc est la base de temps dans AVCodecContext pour le codec utilisé pour un
flux particulier. Il est utilisé pour tous les AVCodecContext et les horodatages associés
.
tbr est deviné à partir du flux vidéo et est la valeur que les utilisateurs veulent voir
lorsqu'ils recherchent la fréquence d'images vidéo, sauf que parfois c'est le double de
ce à quoi on pourrait s'attendre en raison de la fréquence de trame par rapport à la fréquence d'images.
3.3 Base de temps interne AV_TIME_BASE
En plus des trois bases de temps ci-dessus, FFmpeg dispose également d'une base de temps interne AV_TIME_BASE (et AV_TIME_BASE_Q sous forme fractionnaire)
// Internal time base represented as integer
#define AV_TIME_BASE 1000000
// Internal time base represented as fractional value
#define AV_TIME_BASE_Q (AVRational){1, AV_TIME_BASE}
AV_TIME_BASE et AV_TIME_BASE_Q sont utilisés pour le traitement de la fonction interne FFmpeg. La valeur de temps calculée à partir de cette base de temps est exprimée en microsecondes.
3.4 Conversion de format de valeur de temps
av_q2d () convertit le temps de la forme AVRational en forme double. AVRational est un type de fraction, double est un type de nombre à virgule flottante double précision et l'unité de résultat de la conversion est les secondes. Les valeurs avant et après la conversion sont basées sur la même base de temps, seule la représentation de la valeur est différente.
av_q2d () est implémenté comme suit:
/**
* Convert an AVRational to a `double`.
* @param a AVRational to convert
* @return `a` in floating-point form
* @see av_d2q()
*/
static inline double av_q2d(AVRational a){
return a.num / (double) a.den;
}
L'utilisation de av_q2d () est la suivante:
AVStream stream;
AVPacket packet;
packet播放时刻值:timestamp(单位秒) = packet.pts × av_q2d(stream.time_base);
packet播放时长值:duration(单位秒) = packet.duration × av_q2d(stream.time_base);
3.5 Fonction de conversion de base de temps
av_rescale_q () est utilisé pour la conversion de différentes bases de temps, et est utilisé pour convertir la valeur de temps d'une base de temps à une autre base de temps.
/**
* Rescale a 64-bit integer by 2 rational numbers.
*
* The operation is mathematically equivalent to `a × bq / cq`.
*
* This function is equivalent to av_rescale_q_rnd() with #AV_ROUND_NEAR_INF.
*
* @see av_rescale(), av_rescale_rnd(), av_rescale_q_rnd()
*/
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq) av_const;
av_packet_rescale_ts () est utilisé pour convertir diverses valeurs de temps dans AVPacket d'une base de temps à une autre.
/**
* Convert valid timing fields (timestamps / durations) in a packet from one
* timebase to another. Timestamps with unknown values (AV_NOPTS_VALUE) will be
* ignored.
*
* @param pkt packet on which the conversion will be performed
* @param tb_src source timebase, in which the timing fields in pkt are
* expressed
* @param tb_dst destination timebase, to which the timing fields will be
* converted
*/
void av_packet_rescale_ts(AVPacket *pkt, AVRational tb_src, AVRational tb_dst);
3.6 Conversion de base de temps dans le processus de trans-encapsulation
La base de temps dans le conteneur (AVStream.time_base, tbn dans la section 3.2) est définie comme suit:
typedef struct AVStream {
......
/**
* This is the fundamental unit of time (in seconds) in terms
* of which frame timestamps are represented.
*
* decoding: set by libavformat
* encoding: May be set by the caller before avformat_write_header() to
* provide a hint to the muxer about the desired timebase. In
* avformat_write_header(), the muxer will overwrite this field
* with the timebase that will actually be used for the timestamps
* written into the file (which may or may not be related to the
* user-provided one, depending on the format).
*/
AVRational time_base;
......
}
AVStream.time_base AVPacket unit time et le dts pts, le flux d'entrée et le flux de sortie time_base déterminés comme suit:
pour le flux d'entrée: ouvrez le fichier d'entrée, appelez avformat_find_stream_info () peut être acquis dans chaque flux time_base
le flux de sortie: Après ouverture du fichier de sortie, appelez avformat_write_header () pour déterminer la base de temps de chaque flux en fonction du format d'empaquetage du fichier de sortie et écrivez-le dans le fichier de sortie
Différents formats d'emballage ont des bases de temps différentes. Lors du processus de conversion (conversion d'un format d'emballage en un autre), le code pertinent pour la conversion de base de temps est le suivant:
av_read_frame(ifmt_ctx, &pkt);
pkt.pts = av_rescale_q_rnd(pkt.pts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base);
Le code suivant a le même effet que le code ci-dessus:
// 从输入文件中读取packet
av_read_frame(ifmt_ctx, &pkt);
// 将packet中的各时间值从输入流封装格式时间基转换到输出流封装格式时间基
av_packet_rescale_ts(&pkt, in_stream->time_base, out_stream->time_base);
La in_stream->time_base
somme de la base de temps dans le flux ici est la base de temps out_stream->time_base
dans le conteneur, qui est tbn dans la section 3.2.
Par exemple, la base de temps du format de package flv est {1,1000}, et la base de temps du format de package ts est {1,90000}.
Nous écrivons un programme pour convertir le format de package flv au format de package ts, et récupérons les quatre premières images du fichier d'origine (flv) pour afficher l'horodatage:
think@opensuse> ffprobe -show_frames -select_streams v tnmil3.flv | grep pkt_pts
ffprobe version 4.1 Copyright (c) 2007-2018 the FFmpeg developers
Input #0, flv, from 'tnmil3.flv':
Metadata:
encoder : Lavf58.20.100
Duration: 00:00:03.60, start: 0.017000, bitrate: 513 kb/s
Stream #0:0: Video: h264 (High), yuv420p(progressive), 784x480, 25 fps, 25 tbr, 1k tbn, 50 tbc
Stream #0:1: Audio: aac (LC), 44100 Hz, stereo, fltp, 128 kb/s
pkt_pts=80
pkt_pts_time=0.080000
pkt_pts=120
pkt_pts_time=0.120000
pkt_pts=160
pkt_pts_time=0.160000
pkt_pts=200
pkt_pts_time=0.200000
Ensuite, saisissez les quatre premières images du fichier converti (ts) pour afficher l'horodatage:
think@opensuse> ffprobe -show_frames -select_streams v tnmil3.ts | grep pkt_pts
ffprobe version 4.1 Copyright (c) 2007-2018 the FFmpeg developers
Input #0, mpegts, from 'tnmil3.ts':
Duration: 00:00:03.58, start: 0.017000, bitrate: 619 kb/s
Program 1
Metadata:
service_name : Service01
service_provider: FFmpeg
Stream #0:0[0x100]: Video: h264 (High) ([27][0][0][0] / 0x001B), yuv420p(progressive), 784x480, 25 fps, 25 tbr, 90k tbn, 50 tbc
Stream #0:1[0x101]: Audio: aac (LC) ([15][0][0][0] / 0x000F), 44100 Hz, stereo, fltp, 127 kb/s
pkt_pts=7200
pkt_pts_time=0.080000
pkt_pts=10800
pkt_pts_time=0.120000
pkt_pts=14400
pkt_pts_time=0.160000
pkt_pts=18000
pkt_pts_time=0.200000
On constate que pour une même image vidéo, leurs bases de temps (tbn) sont différentes et donc les horodatages (pkt_pts) sont également différents, mais les valeurs de temps calculées (pkt_pts_time) sont les mêmes.
Regardez l'horodatage de la première image, la relation de calcul: 80 × {1,1000} == 7200 × {1,90000} == 0,080000
3.7 Conversion de base de temps pendant le transcodage
La base de temps dans le codec (AVCodecContext.time_base, tbc dans la section 3.2) est définie comme suit:
typedef struct AVCodecContext {
......
/**
* This is the fundamental unit of time (in seconds) in terms
* of which frame timestamps are represented. For fixed-fps content,
* timebase should be 1/framerate and timestamp increments should be
* identically 1.
* This often, but not always is the inverse of the frame rate or field rate
* for video. 1/time_base is not the average frame rate if the frame rate is not
* constant.
*
* Like containers, elementary streams also can store timestamps, 1/time_base
* is the unit in which these timestamps are specified.
* As example of such codec time base see ISO/IEC 14496-2:2001(E)
* vop_time_increment_resolution and fixed_vop_rate
* (fixed_vop_rate == 0 implies that it is different from the framerate)
*
* - encoding: MUST be set by user.
* - decoding: the use of this field for decoding is deprecated.
* Use framerate instead.
*/
AVRational time_base;
......
}
La note ci-dessus souligne que AVCodecContext.time_base est l'inverse de la fréquence d'images (image vidéo) et que l'horodatage de chaque image est incrémenté de 1, puis tbc est égal à la fréquence d'images. Pendant le processus de codage, ce paramètre doit être défini par l'utilisateur. Pendant le processus de décodage, ce paramètre est obsolète. Il est recommandé d'utiliser directement la fréquence d'images réciproque comme base de temps.
Voici une question: selon la note ici, pour un flux vidéo avec une fréquence d'images de 25, tbc devrait être de 25, mais la valeur réelle est de 50. Je ne sais pas quoi expliquer? La tbc est-elle obsolète et n'a pas de signification de référence?
Selon les suggestions dans les commentaires, en utilisation réelle, dans le processus de décodage vidéo, nous n'utilisons pas AVCodecContext.time_base, mais utilisons la fréquence d'images réciproque comme base de temps. Dans le processus d'encodage vidéo, nous définissons AVCodecContext.time_base sur la valeur taux de trame réciproque.
3.7.1 Streaming vidéo
La vidéo est lue image par image, de sorte que la base de temps de l'image vidéo originale après le décodage est de 1 / framerate.
Traitement de conversion de base de temps dans le processus de décodage vidéo:
AVFormatContext *ifmt_ctx;
AVStream *in_stream;
AVCodecContext *dec_ctx;
AVPacket packet;
AVFrame *frame;
// 从输入文件中读取编码帧
av_read_frame(ifmt_ctx, &packet);
// 时间基转换
int raw_video_time_base = av_inv_q(dec_ctx->framerate);
av_packet_rescale_ts(packet, in_stream->time_base, raw_video_time_base);
// 解码
avcodec_send_packet(dec_ctx, packet)
avcodec_receive_frame(dec_ctx, frame);
Traitement de conversion de base de temps dans le processus de codage vidéo:
AVFormatContext *ofmt_ctx;
AVStream *out_stream;
AVCodecContext *dec_ctx;
AVCodecContext *enc_ctx;
AVPacket packet;
AVFrame *frame;
// 编码
avcodec_send_frame(enc_ctx, frame);
avcodec_receive_packet(enc_ctx, packet);
// 时间基转换
packet.stream_index = out_stream_idx;
enc_ctx->time_base = av_inv_q(dec_ctx->framerate);
av_packet_rescale_ts(&opacket, enc_ctx->time_base, out_stream->time_base);
// 将编码帧写入输出媒体文件
av_interleaved_write_frame(o_fmt_ctx, &packet);
3.7.2 Flux audio
L'audio est lu au point d'échantillonnage, donc la base de temps de l'image audio originale après le décodage est 1 / sample_rate
Traitement de conversion de base de temps dans le processus de décodage audio:
AVFormatContext *ifmt_ctx;
AVStream *in_stream;
AVCodecContext *dec_ctx;
AVPacket packet;
AVFrame *frame;
// 从输入文件中读取编码帧
av_read_frame(ifmt_ctx, &packet);
// 时间基转换
int raw_audio_time_base = av_inv_q(dec_ctx->sample_rate);
av_packet_rescale_ts(packet, in_stream->time_base, raw_audio_time_base);
// 解码
avcodec_send_packet(dec_ctx, packet)
avcodec_receive_frame(dec_ctx, frame);
Traitement de conversion de base de temps dans le processus de codage audio:
AVFormatContext *ofmt_ctx;
AVStream *out_stream;
AVCodecContext *dec_ctx;
AVCodecContext *enc_ctx;
AVPacket packet;
AVFrame *frame;
// 编码
avcodec_send_frame(enc_ctx, frame);
avcodec_receive_packet(enc_ctx, packet);
// 时间基转换
packet.stream_index = out_stream_idx;
enc_ctx->time_base = av_inv_q(dec_ctx->sample_rate);
av_packet_rescale_ts(&opacket, enc_ctx->time_base, out_stream->time_base);
// 将编码帧写入输出媒体文件
av_interleaved_write_frame(o_fmt_ctx, &packet);
4. Références
[1]. Que signifie la sortie de ffmpeg? Tbr tbn tbc etc?
[2]. Concepts de base du codage et du décodage vidéo , https://www.cnblogs.com/leisure_chn/p/10285829.html
[3]. Pour ffmpeg Notes sur la compréhension de l'horodatage , https://blog.csdn.net/topsluo/article/details/76239136
[4]. Horodatage et base de temps dans ffmpeg , http://www.imooc.com/article/91381
[ 5]. Explication détaillée des pts impliqués dans l'encodage et le décodage ffmpeg , http://www.52ffmpeg.com/article/353.html
[6]. Problèmes de pts et dts dans l'entrée audio et vidéo , https: // blog. csdn. net / zhouyongku / article / détails / 38510747
5. Dossiers de modification
2019-03-16 V1.0 premier projet
2019-03-23 V1.1 ajoute 3,7 sections