File: ffmpeg_access.c

package info (click to toggle)
lynkeos.app 1.2-3
  • links: PTS
  • area: main
  • in suites: lenny
  • size: 3,892 kB
  • ctags: 256
  • sloc: objc: 7,122; ansic: 695; sh: 206; makefile: 58
file content (356 lines) | stat: -rw-r--r-- 10,340 bytes parent folder | download | duplicates (5)
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
// avcodec_sample.cpp

// A small sample program that shows how to use libavformat and libavcodec to
// read video from a file.
//
// Use
//
// g++ -o avcodec_sample avcodec_sample.cpp -lavformat -lavcodec -lz
//
// to build (assuming libavformat and libavcodec are correctly installed on
// your system).
//
// Run using
//
// avcodec_sample myvideofile.mpg
//
// to write the first five frames from "myvideofile.mpg" to disk in PPM
// format.

#include "ffmpeg_access.h"
#include "avcodec.h"
#include "avformat.h"

#include <stdio.h>


#include <tiffio.h>

#include <errno.h>

typedef int bool;
#define true 1
#define false 0;

static int _ffmpegErrorOccuredFlag;
static char* _ffmpegLastErrorString;


int ffmpegNextFrame(FfmpegMovie* movie){
  AVFormatContext *pFormatCtx;
  AVCodecContext *pCodecCtx;
  int videoStream;
  AVFrame *pFrame;

  pFormatCtx = movie->pFormatCtx;
  pCodecCtx = movie->pCodecCtx;
  videoStream = movie->videoStream;
  pFrame = movie->pCurrentFrame;

  return GetNextFrame(pFormatCtx, pCodecCtx,videoStream,pFrame);
}

int ffmpegConvertCurrentFrame(FfmpegMovie* movie){
  img_convert((AVPicture *)movie->pConvertedFrame, PIX_FMT_RGB24, (AVPicture*)movie->pCurrentFrame,movie->pCodecCtx->pix_fmt,movie->pCodecCtx->width,movie->pCodecCtx->height);
}

int GetNextFrame(AVFormatContext *pFormatCtx, AVCodecContext *pCodecCtx, 
    int videoStream, AVFrame *pFrame)
{
    static AVPacket packet;
    static int      bytesRemaining=0;
    static uint8_t  *rawData;
    static bool     fFirstTime=true;
    int             bytesDecoded;
    int             frameFinished;

    //printf("Getnextframe called \n");

    // First time we're called, set packet.data to NULL to indicate it
    // doesn't have to be freed
    if(fFirstTime)
    {
        fFirstTime=false;
        packet.data=NULL;
    }

    // Decode packets until we have decoded a complete frame
    while(true)
    {
        // Work on the current packet until we have decoded all of it
        while(bytesRemaining > 0)
        {
          // Decode the next chunk of data
          bytesDecoded=avcodec_decode_video(pCodecCtx, pFrame,
                                            &frameFinished, rawData, bytesRemaining);

          //printf("Bytes Remaining: %d    Bytes Decoded: %d \n",bytesRemaining,bytesDecoded);

          // Was there an error?
          if(bytesDecoded < 0)
            {
              fprintf(stderr, "Error while decoding frame\n");
              return false;
            }
          
          bytesRemaining = bytesRemaining - bytesDecoded;
          rawData+=bytesDecoded;
          
          // Did we finish the current frame? Then we can return
          if(frameFinished)
            return true;
        }
        //printf("next packet \n");
        // Read the next packet, skipping all packets that aren't for this
        // stream
        do
        {
            // Free old packet
            if(packet.data!=NULL)
                av_free_packet(&packet);

            // Read new packet
            if(av_read_packet(pFormatCtx, &packet)<0)
                goto loop_exit;
        } while(packet.stream_index!=videoStream);

        bytesRemaining=packet.size;
        rawData=packet.data;
    }

loop_exit:

    // Decode the rest of the last frame
    bytesDecoded=avcodec_decode_video(pCodecCtx, pFrame, &frameFinished, 
        rawData, bytesRemaining);

    // Free last packet
    if(packet.data!=NULL)
        av_free_packet(&packet);

    return frameFinished!=0;
}

void SaveFrame(AVFrame *pFrame, int width, int height, int iFrame)
{
    FILE *pFile;
    char szFilename[32];
    int  y;

    // Open file
    sprintf(szFilename, "frame%d.ppm", iFrame);
    pFile=fopen(szFilename, "wb");
    if(pFile==NULL)
        return;

    // Write header
    fprintf(pFile, "P6 %d %d 255\n", width, height);

    // Write pixel data
    for(y=0; y<height; y++)
        fwrite(pFrame->data[0]+y*pFrame->linesize[0], 1, width*3, pFile);

    // Close file
    fclose(pFile);
}



void ffmpegSetLastErrorOccured(char* msg, int errorCode){
    _ffmpegErrorOccuredFlag = errorCode;
    _ffmpegLastErrorString = msg;
}

int ffmpegInit(){
    // Register all formats and codecs
    av_register_all();
    ffmpegSetLastErrorOccured("No error.",0);
}

int ffmpegErrorOccured(){
  return _ffmpegErrorOccuredFlag;
}
char* ffmpegLastErrorOccured(){
  return _ffmpegLastErrorString;
}


//TODO
void ffmpegMovieBackToStart(FfmpegMovie* movie){

  FfmpegMovie newMovie;

  ffmpegLoadMovie((movie->pFormatCtx->filename),&newMovie);

  av_close_input_file(movie->pFormatCtx);
  avcodec_close(movie->pCodecCtx);
  av_free(((AVPicture *)(movie->pConvertedFrame))->data[0]);
  av_free(movie->pCurrentFrame);
  free(movie->ppmData);

  movie->pFormatCtx = newMovie.pFormatCtx;
  movie->pCodecCtx = newMovie.pCodecCtx;
  movie->videoStream = newMovie.videoStream;
  movie->pCurrentFrame = newMovie.pCurrentFrame;
  movie->pConvertedFrame = newMovie.pConvertedFrame;
  movie->ppmData = newMovie.ppmData;
}


int ffmpegLoadMovie(char* movieName,FfmpegMovie * resultMovie){
    AVFormatContext *pFormatCtx;
    int             i, videoStream;
    AVCodecContext  *pCodecCtx;
    AVCodec         *pCodec;
    int             numBytes;
    uint8_t         *buffer;
    AVFrame         *pFrame; 
    AVFrame         *pFrameRGB;
    char* ppmHeader;
    int size;
    int ret;

    // Open video file
    ret = av_open_input_file(&pFormatCtx, movieName, NULL, 0, NULL);
    if(ret != 0){
      printf("ERROR: Could not open file ");
      printf(movieName);
      printf("    return : %d \n",ret);
      //return -1; // Couldn't open file
      ffmpegSetLastErrorOccured("Couldn't open file.",-1);
      printf("toto 2\n");
      return _ffmpegErrorOccuredFlag;
    }
     

    // Retrieve stream information
    if(av_find_stream_info(pFormatCtx)<0){
      printf("ERROR: Could not retrieve stream operation");
      printf("\n");
      av_close_input_file(pFormatCtx);
      //return -1; // Couldn't find stream information
      ffmpegSetLastErrorOccured("Couldn't find stream information.",-1);
      return _ffmpegErrorOccuredFlag;
    }
     

    // Dump information about file onto standard error
    //dump_format(pFormatCtx, 0, movieName, false);

    // Find the first video stream
    videoStream=-1;
    for(i=0; i<pFormatCtx->nb_streams; i++)
        if(pFormatCtx->streams[i]->codec.codec_type==CODEC_TYPE_VIDEO)
        {
            videoStream=i;
            break;
        }
    if(videoStream==-1){
      printf("ERROR: I didn't find a video stream");
      printf("\n");
      av_close_input_file(pFormatCtx);
      ffmpegSetLastErrorOccured("Didn't find a video stream.",-1);
      //return -1; // Didn't find a video stream
      return _ffmpegErrorOccuredFlag;
    }

    // Get a pointer to the codec context for the video stream
    pCodecCtx=&pFormatCtx->streams[videoStream]->codec;

    // Find the decoder for the video stream
    pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
    if(pCodec==NULL){
      printf("ERROR: Codec not found");
      printf("\n");
      av_close_input_file(pFormatCtx);
      //return -1; // Codec not found
      ffmpegSetLastErrorOccured("Codec not found.",-1);
      return _ffmpegErrorOccuredFlag;
    }

    // Inform the codec that we can handle truncated bitstreams -- i.e.,
    // bitstreams where frame boundaries can fall in the middle of packets
    if(pCodec->capabilities & CODEC_CAP_TRUNCATED){
        pCodecCtx->flags|=CODEC_FLAG_TRUNCATED;
    }

    // Open codec
    if(avcodec_open(pCodecCtx, pCodec)<0){
      printf("ERROR: Can't open the codec");
      printf("\n");
      av_close_input_file(pFormatCtx);
      //return -1; // Could not open codec
      ffmpegSetLastErrorOccured("Could not open codec.",-1);
      return _ffmpegErrorOccuredFlag;
    }

    // Hack to correct wrong frame rates that seem to be generated by some 
    // codecs
    if(pCodecCtx->frame_rate>1000 && pCodecCtx->frame_rate_base==1){
        pCodecCtx->frame_rate_base=1000;
    }

    // Allocate video frame
    pFrame=avcodec_alloc_frame();

    // Allocate an AVFrame structure
    pFrameRGB=avcodec_alloc_frame();

    // Determine required buffer size and allocate buffer
    numBytes=avpicture_get_size(PIX_FMT_RGB24, pCodecCtx->width,pCodecCtx->height);
    buffer = (uint8_t*) malloc(sizeof(uint8_t)*numBytes);
    // Assign appropriate parts of buffer to image planes in pFrameRGB
    avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_RGB24,pCodecCtx->width, pCodecCtx->height);
    
    resultMovie->pFormatCtx = pFormatCtx;
    resultMovie->pCodecCtx = pCodecCtx;
    resultMovie->videoStream = videoStream;
    resultMovie->pCurrentFrame = pFrame;
    resultMovie->pConvertedFrame = pFrameRGB;

    size = asprintf(&ppmHeader,"P6 %d %d 255\n",pCodecCtx->width, pCodecCtx->height);
    size = size + (((pCodecCtx->width)*3)*(pCodecCtx->height));
    resultMovie->ppmData = malloc(size);

    free(ppmHeader);
    ffmpegSetLastErrorOccured("No error.",0);
    return _ffmpegErrorOccuredFlag;
}



int saveTIFFPictureToFile(char* fileName,char* buffer,unsigned int width, unsigned int height){
 // Define an image
  TIFF *image;

  // Open the TIFF file
  if((image = TIFFOpen(fileName, "w")) == NULL){
    printf("Could not open output.tif for writing\n");
   return -1;
  }

  // We need to set some values for basic tags before we can add any data
  TIFFSetField(image, TIFFTAG_IMAGEWIDTH, width);
  TIFFSetField(image, TIFFTAG_IMAGELENGTH, height);
  TIFFSetField(image, TIFFTAG_BITSPERSAMPLE, 16);
  TIFFSetField(image, TIFFTAG_SAMPLESPERPIXEL, 3);
  TIFFSetField(image, TIFFTAG_ROWSPERSTRIP, height);

  TIFFSetField(image, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
  TIFFSetField(image, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
  TIFFSetField(image, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB);
  TIFFSetField(image, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);

  TIFFSetField(image, TIFFTAG_XRESOLUTION, 150.0);
  TIFFSetField(image, TIFFTAG_YRESOLUTION, 150.0);
  TIFFSetField(image, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH);
  
  // Write the information to the file
  printf("Writting file ... %d \n",width*height);
  TIFFWriteEncodedStrip(image, 0, buffer, width*height*6);
  printf("done ...\n");

  // Close the file
  TIFFClose(image);
  return 0;
}