File: Ap4FileWriter.cpp

package info (click to toggle)
kodi-inputstream-adaptive 2.6.14%2Bds1-1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 4,036 kB
  • sloc: cpp: 53,019; ansic: 492; makefile: 10
file content (150 lines) | stat: -rw-r--r-- 5,893 bytes parent folder | download
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
/*****************************************************************
|
|    AP4 - File Writer
|
|    Copyright 2002-2008 Axiomatic Systems, LLC
|
|
|    This file is part of Bento4/AP4 (MP4 Atom Processing Library).
|
|    Unless you have obtained Bento4 under a difference license,
|    this version of Bento4 is Bento4|GPL.
|    Bento4|GPL is free software; you can redistribute it and/or modify
|    it under the terms of the GNU General Public License as published by
|    the Free Software Foundation; either version 2, or (at your option)
|    any later version.
|
|    Bento4|GPL is distributed in the hope that it will be useful,
|    but WITHOUT ANY WARRANTY; without even the implied warranty of
|    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
|    GNU General Public License for more details.
|
|    You should have received a copy of the GNU General Public License
|    along with Bento4|GPL; see the file COPYING.  If not, write to the
|    Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|    02111-1307, USA.
|
 ****************************************************************/

/*----------------------------------------------------------------------
|   includes
+---------------------------------------------------------------------*/
#include "Ap4MoovAtom.h"
#include "Ap4FileWriter.h"
#include "Ap4Movie.h"
#include "Ap4File.h"
#include "Ap4TrakAtom.h"
#include "Ap4Track.h"
#include "Ap4Sample.h"
#include "Ap4DataBuffer.h"
#include "Ap4FtypAtom.h"
#include "Ap4SampleTable.h"

/*----------------------------------------------------------------------
|   AP4_FileWriter::Write
+---------------------------------------------------------------------*/
AP4_Result
AP4_FileWriter::Write(AP4_File& file, AP4_ByteStream& stream, Interleaving /* interleaving */)
{
    // get the file type
    AP4_FtypAtom* file_type = file.GetFileType();

    // write the ftyp atom (always first)
    if (file_type) file_type->Write(stream);

    // write the top-level atoms, except for ftyp, moov and mdat
    for (AP4_List<AP4_Atom>::Item* atom_item = file.GetChildren().FirstItem();
         atom_item;
         atom_item = atom_item->GetNext()) {
        AP4_Atom* atom = atom_item->GetData();
        if (atom->GetType() != AP4_ATOM_TYPE_MDAT &&
            atom->GetType() != AP4_ATOM_TYPE_FTYP &&
            atom->GetType() != AP4_ATOM_TYPE_MOOV) {
            atom->Write(stream);
        }
    }
             
    // get the movie object (and stop if there isn't any)
    AP4_Movie* movie = file.GetMovie();
    if (movie == NULL) return AP4_SUCCESS;

    // see how much we've written so far
    AP4_Position position;
    stream.Tell(position);
    
    // backup and recompute all the chunk offsets
    unsigned int t=0;
    AP4_Result result = AP4_SUCCESS;
    AP4_UI64   mdat_size = AP4_ATOM_HEADER_SIZE;
    AP4_UI64   mdat_position = position+movie->GetMoovAtom()->GetSize();
    AP4_Array<AP4_Array<AP4_UI64>*> trak_chunk_offsets_backup;
    AP4_Array<AP4_UI64>             chunk_offsets;
    for (AP4_List<AP4_Track>::Item* track_item = movie->GetTracks().FirstItem();
         track_item;
         track_item = track_item->GetNext()) {
        AP4_Track*    track = track_item->GetData();
        AP4_TrakAtom* trak  = track->UseTrakAtom();
        
        // backup the chunk offsets
        AP4_Array<AP4_UI64>* chunk_offsets_backup = new AP4_Array<AP4_UI64>();
        trak_chunk_offsets_backup.Append(chunk_offsets_backup);
        result = trak->GetChunkOffsets(*chunk_offsets_backup);
        if (AP4_FAILED(result)) goto end;

        // allocate space for the new chunk offsets
        chunk_offsets.SetItemCount(chunk_offsets_backup->ItemCount());
        
        // compute the new chunk offsets
        AP4_Cardinal     sample_count = track->GetSampleCount();
        AP4_SampleTable* sample_table = track->GetSampleTable();
        AP4_Sample       sample;
        for (AP4_Ordinal i=0; i<sample_count; i++) {
            AP4_Ordinal chunk_index = 0;
            AP4_Ordinal position_in_chunk = 0;
            sample_table->GetSampleChunkPosition(i, chunk_index, position_in_chunk);
            sample_table->GetSample(i, sample);
            if (position_in_chunk == 0) {
                // this sample is the first sample in a chunk, so this is the start of a chunk
                if (chunk_index >= chunk_offsets.ItemCount()) return AP4_ERROR_INTERNAL;
                chunk_offsets[chunk_index] = mdat_position+mdat_size;
            }
            mdat_size += sample.GetSize();
        }        
        result = trak->SetChunkOffsets(chunk_offsets);
    }
    
    // write the moov atom
    movie->GetMoovAtom()->Write(stream);
    
    // create and write the media data (mdat)
    // FIXME: this only supports 32-bit mdat size
    stream.WriteUI32((AP4_UI32)mdat_size);
    stream.WriteUI32(AP4_ATOM_TYPE_MDAT);
    
    // write all tracks and restore the chunk offsets to their backed-up values
    for (AP4_List<AP4_Track>::Item* track_item = movie->GetTracks().FirstItem();
         track_item;
         track_item = track_item->GetNext(), ++t) {
        AP4_Track*    track = track_item->GetData();
        AP4_TrakAtom* trak  = track->UseTrakAtom();
        
        // restore the backed-up chunk offsets
        result = trak->SetChunkOffsets(*trak_chunk_offsets_backup[t]);

        // write all the track's samples
        AP4_Cardinal   sample_count = track->GetSampleCount();
        AP4_Sample     sample;
        AP4_DataBuffer sample_data;
        for (AP4_Ordinal i=0; i<sample_count; i++) {
            track->ReadSample(i, sample, sample_data);
            stream.Write(sample_data.GetData(), sample_data.GetDataSize());
        }
    }

end:
    for (unsigned int i=0; i<trak_chunk_offsets_backup.ItemCount(); i++) {
        delete trak_chunk_offsets_backup[i];
    }
    
    return result;
}