source: trunk/src/objects/RpMediaPlayer.cc @ 1983

Last change on this file since 1983 was 1916, checked in by dkearney, 14 years ago

switching from RpMediaPlayer? to RpVideo? code for the video viewer widget. changed flowdial widget so the dial moved as needed for the video widget.

File size: 8.2 KB
Line 
1/*
2 * ======================================================================
3 *  Rappture::MediaPlayer
4 *
5 *  AUTHOR:  Derrick Kearney, Purdue University
6 *
7 *  Copyright (c) 2005-2010  Purdue Research Foundation
8 * ----------------------------------------------------------------------
9 *  See the file "license.terms" for information on usage and
10 *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
11 * ======================================================================
12 */
13
14#include <cstdlib>
15#include <cstdio>
16#include <cstring>
17#include <cmath>
18#include <fstream>
19#include <assert.h>
20
21#include "RpMediaPlayer.h"
22
23using namespace Rappture;
24
25MediaPlayer::MediaPlayer() :
26    _width (0),
27    _height (0),
28    _bitRate(400000),
29    _frameRate(25.0f),
30    _pFormatCtx(NULL),
31    _videoStream(-1),
32    _pCodecCtx(NULL),
33    _pCodec(NULL),
34    _pFrame(NULL),
35    _pFrameRGB(NULL),
36    _packet(),
37    _buffer(NULL),
38    _swsctx(NULL)
39{
40}
41
42/**
43 * Copy constructor
44 * @param MediaPlayer object to copy
45 */
46 /*
47MediaPlayer::MediaPlayer(const MediaPlayer& o)
48{}
49*/
50
51MediaPlayer::~MediaPlayer()
52{
53    // release();
54}
55
56
57bool
58MediaPlayer::init(Outcome &status, const char *filename)
59{
60    status.addContext("Rappture::MediaPlayer::init()");
61
62    /* Register all codecs and formats */
63    av_register_all();
64    return load(status, filename);
65}
66
67bool
68MediaPlayer::load(Outcome &status, const char *filename)
69{
70    status.addContext("Rappture::MediaPlayer::load()");
71
72    // Open video file
73    if(av_open_input_file(&_pFormatCtx, filename, NULL, 0, NULL)!=0) {
74        status.addError("Could not open file");
75        return false;
76    }
77
78    // Retrieve stream information
79    if(av_find_stream_info(_pFormatCtx)<0) {
80        status.addError("Could not find stream information");
81        return false;
82    }
83
84    // Dump information about file onto standard error
85    dump_format(_pFormatCtx, 0, filename, 0);
86
87    // Find the first video stream
88    _videoStream=-1;
89    for(size_t i=0; i<_pFormatCtx->nb_streams; i++) {
90        if(_pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO) {
91            _videoStream=i;
92            break;
93        }
94    }
95
96    if(_videoStream==-1) {
97        status.addError("Did not find a video stream");
98        return false;
99    }
100
101    // Get a pointer to the codec context for the video stream
102    _pCodecCtx=_pFormatCtx->streams[_videoStream]->codec;
103
104    // Find the decoder for the video stream
105    _pCodec=avcodec_find_decoder(_pCodecCtx->codec_id);
106    if(_pCodec==NULL) {
107        status.addError("Unsupported codec");
108        return false;
109    }
110
111    // Open codec
112    if(avcodec_open(_pCodecCtx, _pCodec)<0) {
113        status.addError("Could not open codec");
114        return false;
115    }
116
117    // Allocate video frame
118    _pFrame=avcodec_alloc_frame();
119
120    // Allocate an AVFrame structure
121    _pFrameRGB=avcodec_alloc_frame();
122    if(_pFrameRGB==NULL) {
123        status.addError("Failed to allocate avcodec frame");
124        return false;
125    }
126
127    // Determine required buffer size and allocate buffer
128    int numBytes=avpicture_get_size(PIX_FMT_RGB24, _pCodecCtx->width,
129                                    _pCodecCtx->height);
130    _buffer=(uint8_t *)av_malloc(numBytes*sizeof(uint8_t));
131
132    // Assign appropriate parts of buffer to image planes in pFrameRGB
133    avpicture_fill((AVPicture *)_pFrameRGB, _buffer, PIX_FMT_RGB24,
134                    _pCodecCtx->width, _pCodecCtx->height);
135
136    /* setup sws context */
137    if (_swsctx == NULL) {
138        _swsctx = sws_getContext(_pCodecCtx->width, _pCodecCtx->height,
139                                 _pCodecCtx->pix_fmt, _pCodecCtx->width,
140                                 _pCodecCtx->height, PIX_FMT_RGB24,
141                                 SWS_BILINEAR, NULL, NULL, NULL);
142        if (_swsctx == NULL) {
143            status.addError("Cannot initialize the conversion context");
144            return false;
145        }
146    }
147
148    return true;
149}
150
151
152bool
153MediaPlayer::release()
154{
155    // status.addContext("Rappture::MediaPlayer::release()");
156
157    // Free the RGB image
158    if (_buffer) {
159        av_free(_buffer);
160        _buffer = NULL;
161    }
162
163    if (_pFrameRGB) {
164        av_free(_pFrameRGB);
165        _pFrameRGB = NULL;
166    }
167
168    // Free the YUV frame
169    if (_pFrame) {
170        av_free(_pFrame);
171        _pFrame = NULL;
172    }
173
174    // Close the codec
175    if (_pCodecCtx) {
176        avcodec_close(_pCodecCtx);
177        _pCodecCtx = NULL;
178    }
179
180    // Close the video file
181    if (_pFormatCtx) {
182        av_close_input_file(_pFormatCtx);
183        _pFormatCtx = NULL;
184    }
185
186    return true;
187}
188
189size_t
190MediaPlayer::read(Outcome &status, SimpleCharBuffer *b)
191{
192    status.addContext("Rappture::MediaPlayer::read()");
193
194    int frameFinished = 0;
195
196    while(av_read_frame(_pFormatCtx, &_packet)>=0) {
197        // Is this a packet from the video stream?
198        if(_packet.stream_index==_videoStream) {
199            // Decode video frame
200            avcodec_decode_video2(_pCodecCtx, _pFrame, &frameFinished,
201                                  &_packet);
202
203            // Did we get a video frame?
204            if (frameFinished) {
205                // Convert the image from its native format to RGB
206                sws_scale(_swsctx,
207                          (const uint8_t * const*)_pFrame->data,
208                          _pFrame->linesize, 0, _pCodecCtx->height,
209                          _pFrameRGB->data, _pFrameRGB->linesize);
210
211                __frame2ppm(b);
212                break;
213            }
214        }
215
216        // Free the packet that was allocated by av_read_frame
217        av_free_packet(&_packet);
218    }
219    return 1;
220}
221
222size_t
223MediaPlayer::nframes() const
224{
225    // status.addContext("Rappture::MediaPlayer::nframes()");
226    return 0;
227}
228/*
229int packet_queue_put(PacketQueue *q, AVPacket *pkt) {
230
231  AVPacketList *pkt1;
232  if(pkt != &flush_pkt && av_dup_packet(pkt) < 0) {
233    return -1;
234  }
235    if(packet_queue_get(&is->audioq, pkt, 1) < 0) {
236      return -1;
237    }
238    if(packet->data == flush_pkt.data) {
239      avcodec_flush_buffers(is->audio_st->codec);
240      continue;
241    }
242*/
243
244
245int
246MediaPlayer::seek(long offset, int whence)
247{
248    // status.addContext("Rappture::MediaPlayer::seek()");
249    int stream_index= -1;
250    int64_t seek_target = is->seek_pos;
251
252    if (is->videoStream >= 0) {
253        stream_index = is->videoStream;
254    } else if (is->audioStream >= 0) {
255        stream_index = is->audioStream;
256    }
257
258    if(stream_index>=0){
259        seek_target= av_rescale_q(seek_target, AV_TIME_BASE_Q,
260                      pFormatCtx->streams[stream_index]->time_base);
261    }
262    if(av_seek_frame(is->pFormatCtx, stream_index,
263                    seek_target, is->seek_flags) < 0) {
264        fprintf(stderr, "%s: error while seeking\n",
265            is->pFormatCtx->filename);
266    } else {
267        /* handle packet queues... more later... */
268        if(is->audioStream >= 0) {
269            packet_queue_flush(&is->audioq);
270            packet_queue_put(&is->audioq, &flush_pkt);
271        }
272        if(is->videoStream >= 0) {
273            packet_queue_flush(&is->videoq);
274            packet_queue_put(&is->videoq, &flush_pkt);
275        }
276    }
277    is->seek_req = 0;
278    return 0;
279}
280
281int
282MediaPlayer::tell() const
283{
284    // status.addContext("Rappture::MediaPlayer::tell()");
285    return 0;
286}
287
288size_t
289MediaPlayer::set(size_t nframes)
290{
291    // status.addContext("Rappture::MediaPlayer::set()");
292    return 0;
293}
294
295bool
296MediaPlayer::good() const
297{
298    // status.addContext("Rappture::MediaPlayer::good()");
299    return true;
300}
301
302bool
303MediaPlayer::bad() const
304{
305    // status.addContext("Rappture::MediaPlayer::bad()");
306    return false;
307}
308
309bool
310MediaPlayer::eof() const
311{
312    // status.addContext("Rappture::MediaPlayer::eof()");
313    return false;
314}
315
316void
317MediaPlayer::__frame2ppm(SimpleCharBuffer *b)
318{
319    // status.addContext("Rappture::MediaPlayer::__frame2ppm()");
320
321    // FIXME: look into using rewind or some other method that
322    //        does not free the already allocated memory. just
323    //        reuses the block.
324    b->clear();
325
326    // Write header
327    b->appendf("P6\n%d %d\n255\n", _pCodecCtx->width, _pCodecCtx->height);
328
329    // Write pixel data
330    for(int y=0; y<_pCodecCtx->height; y++) {
331        // really want to store a void*...
332        b->append((const char *)(_pFrameRGB->data[0]+y*_pFrameRGB->linesize[0]), _pCodecCtx->width*3);
333    }
334}
Note: See TracBrowser for help on using the repository browser.