Κοινή χρήση τεχνολογίας

Ανάπτυξη ήχου και βίντεο—Το FFmpeg εξάγει δεδομένα βίντεο H264 από αρχεία MP4

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

Πώς τα αρχεία MP4 αποθηκεύουν δεδομένα H264

Το αρχείο MP4 είναι μια μορφή κοντέινερ πολυμέσων που μπορεί να περιέχει πολλούς τύπους δεδομένων ήχου και βίντεο, συμπεριλαμβανομένου του βίντεο H.264. Τα αρχεία MP4 χρησιμοποιούν μια ιεραρχική δομή που ονομάζεται "κουτιά" ή "άτομα" για την οργάνωση των δεδομένων. Κάθε κουτί έχει μια συγκεκριμένη λειτουργία και σκοπό για την αποθήκευση μεταδεδομένων αρχείων, δεδομένων ήχου και βίντεο και άλλων πληροφοριών.

Επισκόπηση δομής αρχείων MP4

Τα αρχεία MP4 αποτελούνται από πολλαπλά κουτιά, κάθε πλαίσιο έχει μια κεφαλίδα και περιεχόμενο (ωφέλιμο φορτίο). Η ιεραρχία των κουτιών επιτρέπει στα αρχεία MP4 να αποθηκεύουν και να οργανώνουν τα δεδομένα με ευελιξία. Τα κοινά κουτιά περιλαμβάνουν:

  • ftyp: Πλαίσιο τύπου αρχείου, που περιέχει πληροφορίες μορφής αρχείου.
  • moov: πλαίσιο ταινίας, που περιέχει καθολικά μεταδεδομένα του αρχείου, συμπεριλαμβανομένου του πλαισίου trak (track).
  • mdat: Πλαίσιο δεδομένων πολυμέσων, που περιέχει πραγματικά δεδομένα ήχου και βίντεο.
  • moof: Κουτί κλιπ ταινίας, που περιέχει μεταδεδομένα κλιπ, για ροή.

Αποθήκευση δεδομένων H.264 σε MP4

Τα δεδομένα βίντεο H.264 συνήθως αποθηκεύονται σετρακστο κουτί, συγκεκριμένα στοmdia(μεσο ΜΑΖΙΚΗΣ ΕΝΗΜΕΡΩΣΗΣ),minf(πληροφορίες μέσων ενημέρωσης),stbl (Πίνακας παραδείγματος) υποπλαίσιο. Ακολουθεί η λεπτομερής μέθοδος αποθήκευσης:

1. κουτί ftyp

ftypΤο πλαίσιο περιέχει πληροφορίες τύπου αρχείου και συμβατότητας που υποδεικνύουν τη μορφή και την έκδοση του αρχείου.

2. moov κουτί

moovΤα πλαίσια περιέχουν καθολικά μεταδεδομένα, συμπεριλαμβανομένων των ακόλουθων βασικών υποπλαισίων:

  • mvhd: Πλαίσιο κεφαλίδας ταινίας, που περιέχει την παγκόσμια ώρα και άλλες πληροφορίες.
  • τρακ: Πλαίσιο κομματιού, κάθε κομμάτι αντιστοιχεί σε ροή πολυμέσων (ήχος, βίντεο, υπότιτλοι κ.λπ.).
    • tkhd:Πλαίσιο κεφαλίδας κομματιού, που περιέχει την ώρα του κομματιού και άλλες πληροφορίες.
    • mdia: Πλαίσιο πολυμέσων, που περιέχει πληροφορίες πολυμέσων για ένα συγκεκριμένο κομμάτι.
      • mdhd: Πλαίσιο κεφαλίδας πολυμέσων, που περιέχει την ώρα και άλλες πληροφορίες του μέσου.
      • hdlr: Πλαίσιο αναφοράς επεξεργαστή, που καθορίζει τον τύπο δεδομένων του κομματιού (βίντεο, ήχος, κ.λπ.).
      • minf: Πλαίσιο πληροφοριών πολυμέσων, που περιέχει πληροφορίες για συγκεκριμένα μέσα.
        • vmhd: Πλαίσιο κεφαλίδας πληροφοριών πολυμέσων βίντεο, που χρησιμοποιείται μόνο για κομμάτια βίντεο.
        • dinf: Πλαίσιο αναφοράς δεδομένων, που περιέχει πίνακα αναφοράς δεδομένων.
          • Dref: Πλαίσιο πίνακα αναφοράς δεδομένων, που περιέχει αναφορές σε δεδομένα πολυμέσων.
        • stbl: Δείγμα πίνακα πίνακα, που περιέχει περιγραφή δείγματος, ώρα, τοποθεσία και άλλες πληροφορίες.
          • stsd: Παράδειγμα πλαισίου περιγραφής, συμπεριλαμβανομένου του τύπου κωδικοποίησης και των λεπτομερειών.
            • avc1: Περιέχει πληροφορίες αποκωδικοποίησης βίντεο H.264.
          • stts: Πίνακας δειγματοληψίας χρόνου, που περιέχει πληροφορίες χρονικής σήμανσης πλαισίου.
          • stsc: Παράδειγμα πίνακα αντιστοίχισης μπλοκ, που ορίζει τον τρόπο αντιστοίχισης των παραδειγμάτων σε μπλοκ.
          • stsz: Πίνακας μεγεθών δείγματος, που περιέχει το μέγεθος κάθε δείγματος.
          • stco: Αποκλεισμός πίνακα μετατόπισης, που περιέχει τη μετατόπιση του μπλοκ δεδομένων στο πλαίσιο mdat.
3. κουτί mdat

mdat Το πλαίσιο περιέχει τα πραγματικά δεδομένα πολυμέσων, συμπεριλαμβανομένων των δεδομένων βίντεο H.264. Αυτό διαφέρει από τη μορφή του Παραρτήματος-Β.Τα δεδομένα βίντεο συνήθως δεν περιέχουν κωδικό έναρξης μονάδας NAL, αλλά χρησιμοποιούν ένα πεδίο μήκους.

Αποθήκευση δεδομένων H.264 σε κουτί stsd (AVC1)

stsdΛεπτομερείς πληροφορίες σχετικά με τη ροή H.264, συμπεριλαμβανομένων των δεδομένων SPS και PPS, αποθηκεύονται στο (πλαίσιο περιγραφής δείγματος):

  • avc1: Περιγραφή τύπου κωδικοποίησης βίντεο, συμπεριλαμβανομένων λεπτομερών πληροφοριών για το βίντεο H.264.
    • AVCDecoderConfigurationRecord: Περιέχει δεδομένα SPS και PPS, καθώς και πληροφορίες μήκους μονάδων NAL.

Η διαφορά μεταξύ της μορφής AVC1 και του Παραρτήματος-Β (γυμνή ροή H.264)

Κωδικός έναρξης έναντι πεδίου μήκους

  • Μορφή AVC1 : Υπάρχει ένα πεδίο μήκους πριν από κάθε μονάδα NAL, που υποδεικνύει το μέγεθος της μονάδας NAL.Το μέγεθος του πεδίου μήκους δίνεται απόlengthSizeMinusOne Προσδιορίστε, συνήθως 4 byte.
  • Μορφή παραρτήματος-Β: Υπάρχει ένας κωδικός έναρξης πριν από κάθε μονάδα NAL 0x00000001 ή0x000001, χρησιμοποιείται για τον προσδιορισμό των ορίων των μονάδων NAL.

Αποθήκευση δεδομένων SPS και PPS

  • Μορφή AVC1: Τα δεδομένα SPS και PPS αποθηκεύονται σε AVCDecoderConfigurationRecord , και αναλύεται όταν αρχικοποιείται ο αποκωδικοποιητής.
  • Μορφή παραρτήματος-Β: Τα δεδομένα SPS και PPS περιλαμβάνονται απευθείας στη ροή, συνήθως πριν από τα βασικά καρέ για να διασφαλιστεί ότι ο αποκωδικοποιητής μπορεί να τα αναλύσει σωστά.

χρήση

  • Μορφή AVC1: Χρησιμοποιείται κυρίως για MP4 και άλλες μορφές συσκευασίας,Παρέχετε αποτελεσματικές δυνατότητες αποθήκευσης και τυχαίας πρόσβασης
  • Μορφή παραρτήματος-Β: Χρησιμοποιείται κυρίωςΕφαρμογές γυμνής ροής και ζωντανής ροής, για τη διευκόλυνση της αναγνώρισης και εξαγωγής μονάδων NAL.

Βήματα για την εξαγωγή γυμνής ροής H264 από αρχεία MP4:

Εισαγάγετε την περιγραφή της εικόνας εδώ

Παράδειγμα πλήρους κώδικα:

#include <stdio.h>
#include <libavutil/log.h>
#include <libavformat/avio.h>
#include <libavformat/avformat.h>

#ifndef AV_WB32
#   define AV_WB32(p, val) do {                 
        uint32_t d = (val);                     
        ((uint8_t*)(p))[3] = (d);               
        ((uint8_t*)(p))[2] = (d)>>8;            
        ((uint8_t*)(p))[1] = (d)>>16;           
        ((uint8_t*)(p))[0] = (d)>>24;           
    } while(0)
#endif


//读取内存中以大端字节序(big-endian)存储的16位无符号整数
#ifndef AV_RB16
#   define AV_RB16(x)                           
    ((((const uint8_t*)(x))[0] << 8) |          
      ((const uint8_t*)(x))[1])
#endif

static int alloc_and_copy(AVPacket *out,
                          const uint8_t *sps_pps, uint32_t sps_pps_size,
                          const uint8_t *in, uint32_t in_size)
{
    uint32_t offset         = out->size;
    uint8_t nal_header_size = offset ? 3 : 4;
    int err;

    err = av_grow_packet(out, sps_pps_size + in_size + nal_header_size);
    if (err < 0)
        return err;

    if (sps_pps)
        memcpy(out->data + offset, sps_pps, sps_pps_size);
    memcpy(out->data + sps_pps_size + nal_header_size + offset, in, in_size);
    if (!offset) {
        AV_WB32(out->data + sps_pps_size, 1);
    } else {
        (out->data + offset + sps_pps_size)[0] =
        (out->data + offset + sps_pps_size)[1] = 0;
        (out->data + offset + sps_pps_size)[2] = 1;
    }

    return 0;
}

//将 H.264 编码器的 extradata (额外数据),从 MP4/AVCC 格式转换为 Annex-B 格式,并将其存储在 AVPacket 结构中。
int h264_extradata_to_annexb(const uint8_t *codec_extradata, const int codec_extradata_size, AVPacket *out_extradata, int padding)
{
    uint16_t unit_size;
    uint64_t total_size                 = 0;
    uint8_t *out                        = NULL, unit_nb, sps_done = 0,
             sps_seen                   = 0, pps_seen = 0, sps_offset = 0, pps_offset = 0;
    const uint8_t *extradata            = codec_extradata + 4;
    // 跳过AVCC 格式中的前四个字节,这些信息在解析NAL单元的时候并不需要
    static const uint8_t nalu_header[4] = { 0, 0, 0, 1 }; //填充起始码
    int length_size = (*extradata++ & 0x3) + 1; // retrieve length coded size, 用于指示表示编码数据长度所需字节数

    sps_offset = pps_offset = -1;

    /* retrieve sps and pps unit(s) */
    unit_nb = *extradata++ & 0x1f; /* number of sps unit(s) */
    if (!unit_nb) {
        goto pps;
    }else {
        sps_offset = 0;
        sps_seen = 1;
    }

    while (unit_nb--) {
        int err;

        unit_size   = AV_RB16(extradata);
        total_size += unit_size + 4;
        if (total_size > INT_MAX - padding) {
            av_log(NULL, AV_LOG_ERROR,
                   "Too big extradata size, corrupted stream or invalid MP4/AVCC bitstreamn");
            av_free(out);
            return AVERROR(EINVAL);
        }
        if (extradata + 2 + unit_size > codec_extradata + codec_extradata_size) {
            av_log(NULL, AV_LOG_ERROR, "Packet header is not contained in global extradata, "
                   "corrupted stream or invalid MP4/AVCC bitstreamn");
            av_free(out);
            return AVERROR(EINVAL);
        }
        if ((err = av_reallocp(&out, total_size + padding)) < 0)
            return err;
        memcpy(out + total_size - unit_size - 4, nalu_header, 4);
        memcpy(out + total_size - unit_size, extradata + 2, unit_size);
        extradata += 2 + unit_size;
pps:
        if (!unit_nb && !sps_done++) {
            unit_nb = *extradata++; /* number of pps unit(s) */
            if (unit_nb) {
                pps_offset = total_size;
                pps_seen = 1;
            }
        }
    }

    if (out)
        memset(out + total_size, 0, padding);

    if (!sps_seen)
        av_log(NULL, AV_LOG_WARNING,
               "Warning: SPS NALU missing or invalid. "
               "The resulting stream may not play.n");

    if (!pps_seen)
        av_log(NULL, AV_LOG_WARNING,
               "Warning: PPS NALU missing or invalid. "
               "The resulting stream may not play.n");

    out_extradata->data      = out;
    out_extradata->size      = total_size;

    return length_size;
}
//将MP4中的AVCC格式转为annexb格式
int h264_mp4toannexb(AVFormatContext *fmt_ctx, AVPacket *in, FILE *dst_fd)
{

    AVPacket *out = NULL;
    AVPacket spspps_pkt;

    int len;
    uint8_t unit_type;
    int32_t nal_size;
    uint32_t cumul_size    = 0;
    const uint8_t *buf;
    const uint8_t *buf_end;
    int            buf_size;
    int ret = 0, i;

    out = av_packet_alloc();  // 

    buf      = in->data;
    buf_size = in->size;
    buf_end  = in->data + in->size;

    do {
        ret= AVERROR(EINVAL);
        if (buf + 4 /*s->length_size*/ > buf_end)
            goto fail;

        for (nal_size = 0, i = 0; i<4/*s->length_size*/; i++)
            nal_size = (nal_size << 8) | buf[i];

        buf += 4; /*s->length_size;*/
        unit_type = *buf & 0x1f;  //确定单元类型

        if (nal_size > buf_end - buf || nal_size < 0)
            goto fail;

        /*
        if (unit_type == 7)
            s->idr_sps_seen = s->new_idr = 1;
        else if (unit_type == 8) {
            s->idr_pps_seen = s->new_idr = 1;
            */
            /* if SPS has not been seen yet, prepend the AVCC one to PPS */
            /*
            if (!s->idr_sps_seen) {
                if (s->sps_offset == -1)
                    av_log(ctx, AV_LOG_WARNING, "SPS not present in the stream, nor in AVCC, stream may be unreadablen");
                else {
                    if ((ret = alloc_and_copy(out,
                                         ctx->par_out->extradata + s->sps_offset,
                                         s->pps_offset != -1 ? s->pps_offset : ctx->par_out->extradata_size - s->sps_offset,
                                         buf, nal_size)) < 0)
                        goto fail;
                    s->idr_sps_seen = 1;
                    goto next_nal;
                }
            }
        }
        */

        /* if this is a new IDR picture following an IDR picture, reset the idr flag.
         * Just check first_mb_in_slice to be 0 as this is the simplest solution.
         * This could be checking idr_pic_id instead, but would complexify the parsing. */
        /*
        if (!s->new_idr && unit_type == 5 && (buf[1] & 0x80))
            s->new_idr = 1;

        */
        /* prepend only to the first type 5 NAL unit of an IDR picture, if no sps/pps are already present */
        if (/*s->new_idr && */unit_type == 5 /*&& !s->idr_sps_seen && !s->idr_pps_seen*/) {

            //说明是个关键帧,需要将MP4中的SPS/PPS 填充到NAL单元之前    

            h264_extradata_to_annexb( fmt_ctx->streams[in->stream_index]->codec->extradata,
                                      fmt_ctx->streams[in->stream_index]->codec->extradata_size,
                                      &spspps_pkt,
                                      AV_INPUT_BUFFER_PADDING_SIZE);

            if ((ret=alloc_and_copy(out,
                               spspps_pkt.data, spspps_pkt.size,
                               buf, nal_size)) < 0)
                goto fail;
            /*s->new_idr = 0;*/
        /* if only SPS has been seen, also insert PPS */
        }
        /*else if (s->new_idr && unit_type == 5 && s->idr_sps_seen && !s->idr_pps_seen) {
            if (s->pps_offset == -1) {
                av_log(ctx, AV_LOG_WARNING, "PPS not present in the stream, nor in AVCC, stream may be unreadablen");
                if ((ret = alloc_and_copy(out, NULL, 0, buf, nal_size)) < 0)
                    goto fail;
            } else if ((ret = alloc_and_copy(out,
                                        ctx->par_out->extradata + s->pps_offset, ctx->par_out->extradata_size - s->pps_offset,
                                        buf, nal_size)) < 0)
                goto fail;
        }*/ else {
            if ((ret=alloc_and_copy(out, NULL, 0, buf, nal_size)) < 0)
                goto fail;
            /*
            if (!s->new_idr && unit_type == 1) {
                s->new_idr = 1;
                s->idr_sps_seen = 0;
                s->idr_pps_seen = 0;
            }
            */
        }


        len = fwrite( out->data, 1, out->size, dst_fd);
        if(len != out->size){
            av_log(NULL, AV_LOG_DEBUG, "warning, length of writed data isn't equal pkt.size(%d, %d)n",
                    len,
                    out->size);
        }
        fflush(dst_fd);

next_nal:
        buf        += nal_size;
        cumul_size += nal_size + 4;//s->length_size;
    } while (cumul_size < buf_size);

    /*
    ret = av_packet_copy_props(out, in);
    if (ret < 0)
        goto fail;

    */
fail:
    av_packet_free(&out);

    return ret;
}

int main(int argc, char *argv[])
{
    int err_code;
    char errors[1024];

    char *src_filename = NULL;
    char *dst_filename = NULL;

    FILE *dst_fd = NULL;

    int video_stream_index = -1;

    //AVFormatContext *ofmt_ctx = NULL;
    //AVOutputFormat *output_fmt = NULL;
    //AVStream *out_stream = NULL;

    AVFormatContext *fmt_ctx = NULL;
    AVPacket pkt;

    //AVFrame *frame = NULL;

    av_log_set_level(AV_LOG_DEBUG);

    if(argc < 3){
        av_log(NULL, AV_LOG_DEBUG, "the count of parameters should be more than three!n");
        return -1;
    }

    src_filename = argv[1];
    dst_filename = argv[2];

    if(src_filename == NULL || dst_filename == NULL){
        av_log(NULL, AV_LOG_ERROR, "src or dts file is null, plz check them!n");
        return -1;
    }

    /*register all formats and codec*/
    av_register_all();

    dst_fd = fopen(dst_filename, "wb");
    if (!dst_fd) {
        av_log(NULL, AV_LOG_DEBUG, "Could not open destination file %sn", dst_filename);
        return -1;
    }

    /*open input media file, and allocate format context*/
    if((err_code = avformat_open_input(&fmt_ctx, src_filename, NULL, NULL)) < 0){
        av_strerror(err_code, errors, 1024);
        av_log(NULL, AV_LOG_DEBUG, "Could not open source file: %s, %d(%s)n",
               src_filename,
               err_code,
               errors);
        return -1;
    }

    /*dump input information*/
    av_dump_format(fmt_ctx, 0, src_filename, 0);

    /*initialize packet*/
    av_init_packet(&pkt);
    pkt.data = NULL;
    pkt.size = 0;

    /*find best video stream*/
    video_stream_index = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
    if(video_stream_index < 0){
        av_log(NULL, AV_LOG_DEBUG, "Could not find %s stream in input file %sn",
               av_get_media_type_string(AVMEDIA_TYPE_VIDEO),
               src_filename);
        return AVERROR(EINVAL);
    }

    /*
    if (avformat_write_header(ofmt_ctx, NULL) < 0) {
        av_log(NULL, AV_LOG_DEBUG, "Error occurred when opening output file");
        exit(1);
    }
    */

    /*read frames from media file*/
    while(av_read_frame(fmt_ctx, &pkt) >=0 ){
        if(pkt.stream_index == video_stream_index){
            /*
            pkt.stream_index = 0;
            av_write_frame(ofmt_ctx, &pkt);
            av_free_packet(&pkt);
            */

            h264_mp4toannexb(fmt_ctx, &pkt, dst_fd);

        }

        //release pkt->data
        av_packet_unref(&pkt);
    }

    //av_write_trailer(ofmt_ctx);

    /*close input media file*/
    avformat_close_input(&fmt_ctx);
    if(dst_fd) {
        fclose(dst_fd);
    }

    //avio_close(ofmt_ctx->pb);

    return 0;
}

  • 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
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363