~ubuntu-branches/debian/sid/avifile/sid

« back to all changes in this revision

Viewing changes to .pc/ffmpeg.patch/plugins/libffmpeg/FFVideoDecoder.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Alessio Treglia
  • Date: 2011-05-06 10:30:19 UTC
  • Revision ID: james.westby@ubuntu.com-20110506103019-yoq1hpe02tywmx6o
Tags: 1:0.7.48~20090503.ds-3
* QA upload.
* Fix FTBFS with GCC4.5 (Closes: #564868).
* debian/control:
  - Fix duplicate-in-relation-field in avifile-win32-plugin
    depends: ${shlibs:Depends}.
  - Fix debhelper-but-no-misc-depends avifile-win32-plugin.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include "FFVideoDecoder.h"
 
2
#include "fillplugins.h"
 
3
#include "plugin.h"
 
4
#include "avm_output.h"
 
5
 
 
6
#include <string.h>
 
7
#include <stdlib.h> // free
 
8
#include <stdio.h>
 
9
 
 
10
#if 0
 
11
#define FFTIMING(a) a
 
12
#include "avm_cpuinfo.h"
 
13
#include "utils.h"
 
14
static float ftm = 0;
 
15
#else
 
16
#define FFTIMING(a)
 
17
#endif
 
18
 
 
19
#define Debug if (0)
 
20
 
 
21
AVM_BEGIN_NAMESPACE;
 
22
 
 
23
FFVideoDecoder::FFVideoDecoder(AVCodec* av, const CodecInfo& info, const BITMAPINFOHEADER& bh, int flip)
 
24
    :IVideoDecoder(info, bh), m_pAvCodec(av), m_pAvContext(0),
 
25
    m_Caps((CAPS)(CAP_YV12 | CAP_ALIGN16)), m_uiBuffers(0), m_bRestart(true),
 
26
    m_Order(20), m_pImg(0), m_bUsed(false)
 
27
{
 
28
    m_Dest.SetSpace(fccYV12);
 
29
    // not supported if (flip) m_Dest.biHeight *= -1;
 
30
    Flush();
 
31
 
 
32
    //m_pAvStream = (struct AVStream*)bh.biXPelsPerMeter; Debug printf("Context %p\n", m_pAvStream);
 
33
    if (0 && m_pFormat->biCompression == fccHFYU)
 
34
    {
 
35
        // for now disabled
 
36
        m_pAvCodec->capabilities &= ~(CODEC_CAP_DRAW_HORIZ_BAND | CODEC_CAP_DR1);
 
37
        AVM_WRITE(m_Info.GetPrivateName(), "if you have troubles - use Win32 codec instead\n");
 
38
        m_Caps = (CAPS) (m_Caps | CAP_YUY2);
 
39
    }
 
40
}
 
41
 
 
42
FFVideoDecoder::~FFVideoDecoder()
 
43
{
 
44
    Stop();
 
45
    FFTIMING(printf("ftm %f\n", ftm));
 
46
}
 
47
 
 
48
void FFVideoDecoder::Flush()
 
49
{
 
50
    Debug printf("\nFF: Flush\n\n");
 
51
    if (m_pAvContext)
 
52
        avcodec_flush_buffers(m_pAvContext);
 
53
    m_bFlushed = true;
 
54
    m_Order.clear();
 
55
    //m_iAgeB = m_iAgeIP[0] = m_iAgeIP[1] = (1 << 30);
 
56
}
 
57
 
 
58
// callback to draw horizontal slice
 
59
static void draw_slice(struct AVCodecContext *avctx,
 
60
                       const AVFrame *src, int offset[4],
 
61
                       int y, int type, int height)
 
62
{
 
63
    FFVideoDecoder* d = (FFVideoDecoder*) avctx->opaque;
 
64
    ci_surface_t ci;
 
65
    ci.m_pPlane[0] = src->data[0] + offset[0];
 
66
    ci.m_pPlane[1] = src->data[2] + offset[2];
 
67
    ci.m_pPlane[2] = src->data[1] + offset[1];
 
68
    ci.m_iStride[0] = src->linesize[0];
 
69
    ci.m_iStride[1] = src->linesize[2];
 
70
    ci.m_iStride[2] = src->linesize[1];
 
71
    ci.m_iWidth = ci.m_Window.w = avctx->width;
 
72
    ci.m_iHeight = ci.m_Window.h = height;
 
73
    ci.m_Window.x = 0;
 
74
    ci.m_Window.y = y;
 
75
    ci.m_iFormat = IMG_FMT_YV12;
 
76
    //printf("DrawSlice %p   %p    y:%d w:%d h:%d\n", d->m_pImg, src, ci.m_Window.y, ci.m_Window.w, height);
 
77
    d->m_pImg->Slice(&ci);
 
78
}
 
79
 
 
80
// callback to supply rendering buffer to ffmpeg
 
81
static int get_buffer(AVCodecContext* avctx, AVFrame* pic)
 
82
{
 
83
    static const char ftypes[][3] = { "I", "P", "B", "S", "SI", "SP" };
 
84
 
 
85
    FFVideoDecoder* d = (FFVideoDecoder*) avctx->opaque;
 
86
    CImage* pImage = d->m_pImg;
 
87
    if ((avctx->pix_fmt != PIX_FMT_YUV420P
 
88
        && avctx->pix_fmt != PIX_FMT_YUVJ420P)
 
89
        || !pImage || !d->m_bDirect)
 
90
    {
 
91
        Debug printf("FF: Unsupported pixel format for Dr1 %d\n", avctx->pix_fmt); //abort();
 
92
        return avcodec_default_get_buffer(avctx, pic);
 
93
    }
 
94
 
 
95
    d->m_bUsed = true;
 
96
    Debug if (pic->buffer_hints) printf("FF bufhints 0x%x\n", pic->buffer_hints);
 
97
 
 
98
    pic->opaque = pImage;
 
99
#if 0
 
100
        {
 
101
            const uint8_t b[3] = { 0x10, 0x80, 0x80 };
 
102
            for (int j = 0; j < 3; ++j) {
 
103
                uint8_t c = b[j];
 
104
                fprintf(stderr, "CLEANbuff   b:%d   p:%p   c:%x\n", pImage->Stride(j), pImage->Data(j), c);
 
105
                for (unsigned i = 0; i < pImage->Stride(j); ++i) pImage->Data(j)[i] = c;
 
106
            }
 
107
        }
 
108
#endif
 
109
    // we are using YV12 - ffmpeg uses I420
 
110
    pic->data[0] = pImage->Data(0);
 
111
    pic->data[1] = pImage->Data(2);
 
112
    pic->data[2] = pImage->Data(1);
 
113
    pic->linesize[0] = pImage->Stride(0);
 
114
    pic->linesize[1] = pImage->Stride(2); // Note: for ffmpeg linsize[1] == linesize[2]!
 
115
    pic->linesize[2] = pImage->Stride(1);
 
116
    pic->pts = pImage->m_lTimestamp;
 
117
    pic->type = FF_BUFFER_TYPE_USER;
 
118
    pImage->m_iType = pic->pict_type;
 
119
 
 
120
    pic->age = (pImage->GetAge() != pImage->MAX_AGE) ? pic->coded_picture_number - pImage->GetAge() : (1 << 30);
 
121
    if (pic->reference)
 
122
        pImage->Age(pic->coded_picture_number);
 
123
    else
 
124
        pImage->Age();
 
125
 
 
126
    Debug printf("FF: <<<< GetBuffer %p  %s %dx%d %p:%p:%p s:%f f:%d r:%d  age:%d\n", pImage, ftypes[pic->pict_type],
 
127
                 avctx->width, avctx->height, pImage->Data(0), pImage->Data(2), pImage->Data(1),
 
128
                 (double)pImage->m_lTimestamp / 1000000., avctx->pix_fmt, pic->reference, pic->age);
 
129
    return 0;
 
130
}
 
131
 
 
132
static void release_buffer(struct AVCodecContext* avctx, AVFrame* pic)
 
133
{
 
134
    if (pic->type == FF_BUFFER_TYPE_USER)
 
135
    {
 
136
        FFVideoDecoder* d = (FFVideoDecoder*) avctx->opaque;
 
137
        d->m_pReleased = (CImage*) pic->opaque;
 
138
        Debug printf("FF: >>>> Released buffer %p  %p\n", pic->opaque, pic);
 
139
        memset(pic->data, 0, sizeof(void*) * 4);
 
140
        pic->opaque = NULL;
 
141
    }
 
142
    else
 
143
    {
 
144
        Debug printf(">>>> released default buffer *****************\n");
 
145
        avcodec_default_release_buffer(avctx, pic);
 
146
    }
 
147
}
 
148
 
 
149
int FFVideoDecoder::DecodeFrame(CImage* pImage, const void* src, size_t size,
 
150
                                int is_keyframe, bool render, CImage** pOut)
 
151
{
 
152
    FFTIMING(int64_t ts = avm_get_time_us());
 
153
    if (//(m_bFlushed && !is_keyframe) ||
 
154
        (pImage && pImage->GetAllocator()
 
155
            && m_uiBuffers != pImage->GetAllocator()->GetImages())
 
156
        || m_bRestart)
 
157
    {
 
158
        //printf("RES %d  %" PRIsz "   %" PRIsz "\n", m_bRestart, m_uiBuffers, pImage->GetAllocator()->GetImages());
 
159
        Stop();
 
160
    }
 
161
 
 
162
    //printf("FFMPEG space %p \n", m_pAvContext); m_Dest.Print(); pImage->GetFmt()->Print();
 
163
    if (!m_pAvContext)
 
164
    {
 
165
        if (!(m_pAvContext = avcodec_alloc_context2(m_pAvCodec->type)))
 
166
            return -1;
 
167
        // for autodetection errors
 
168
        m_pAvContext->codec_tag = m_pFormat->biCompression;
 
169
        m_pAvContext->bits_per_coded_sample = m_pFormat->biBitCount;
 
170
        m_pAvContext->width = m_Dest.biWidth;
 
171
        m_pAvContext->height = (m_Dest.biHeight < 0) ? -m_Dest.biHeight : m_Dest.biHeight;
 
172
 
 
173
        if (m_pFormat->biSize > sizeof(BITMAPINFOHEADER))
 
174
        {
 
175
            m_pAvContext->extradata_size = int(m_pFormat->biSize - sizeof(BITMAPINFOHEADER));
 
176
            m_pAvContext->extradata = (uint8_t*)m_pFormat + sizeof(BITMAPINFOHEADER);
 
177
            if (m_pAvContext->extradata_size > 40)
 
178
                m_pAvContext->flags |= CODEC_FLAG_EXTERN_HUFF; // somewhat useless
 
179
        }
 
180
 
 
181
        m_uiBuffers = (pImage && pImage->GetAllocator()) ? pImage->GetAllocator()->GetImages() : 0;
 
182
        //printf("IMAGES %d\n", m_uiBuffers);
 
183
        // for SVQ1 - align 63 will be needed FIXME
 
184
        int v = 0;
 
185
        const char* drtxt = "doesn't support";
 
186
 
 
187
        m_bDirect = false;
 
188
        if (m_pAvCodec->capabilities & CODEC_CAP_DR1)
 
189
        {
 
190
            drtxt = "not using";
 
191
            if (pImage)
 
192
            {
 
193
                size_t require = 2;
 
194
                //fprintf(stderr, "buff  %" PRIsz "  %" PRIsz "\n", m_uiBuffers, require);
 
195
                switch (m_Info.fourcc)
 
196
                {
 
197
                case fccDVSD:
 
198
                    require = 1;
 
199
                    break;
 
200
                }
 
201
                if (m_Info.FindAttribute(ffstr_dr1)
 
202
                    && PluginGetAttrInt(m_Info, ffstr_dr1, &v) == 0 && v
 
203
                    && pImage->Format() == IMG_FMT_YV12)
 
204
                {
 
205
                    // for DR we needs some special width aligment
 
206
                    // also there are some more limitation
 
207
                    m_pAvContext->flags |= CODEC_FLAG_EMU_EDGE;
 
208
                    drtxt = "using";
 
209
                    m_bDirect = true;
 
210
                    //m_pAvContext->skip_top = 32;
 
211
                    /*
 
212
                    m_pAvContext->skip_loop_filter = AVDISCARD_BIDIR;
 
213
                    m_pAvContext->skip_idct = AVDISCARD_BIDIR;
 
214
                    m_pAvContext->skip_frame = AVDISCARD_BIDIR;
 
215
                    */
 
216
                    m_pAvContext->get_buffer = get_buffer;
 
217
                    m_pAvContext->reget_buffer = get_buffer;
 
218
                    m_pAvContext->release_buffer = release_buffer;
 
219
                }
 
220
            }
 
221
        }
 
222
        if (m_bRestart)
 
223
            AVM_WRITE(m_Info.GetPrivateName(), "%s DR1\n", drtxt);
 
224
        m_bRestart = false;
 
225
 
 
226
#if 0
 
227
        if (m_Info.fourcc == RIFFINFO_MPG1
 
228
            && m_pAvCodec->capabilities & CODEC_CAP_TRUNCATED)
 
229
            m_pAvContext->flags |= CODEC_FLAG_TRUNCATED;
 
230
#endif
 
231
 
 
232
#if 1
 
233
        m_pAvContext->error_recognition = FF_ER_COMPLIANT;
 
234
        m_pAvContext->error_concealment = FF_EC_GUESS_MVS;
 
235
        m_pAvContext->workaround_bugs = FF_BUG_AUTODETECT;
 
236
#endif
 
237
#if 0
 
238
        if (codec->options) {
 
239
            avm::vector<AttributeInfo>::const_iterator it;
 
240
            for (it = m_Info.decoder_info.begin();
 
241
                 it != m_Info.decoder_info.end(); it++)
 
242
            {
 
243
                char b[100];
 
244
                float f;
 
245
                b[0] = 0;
 
246
                switch (it->GetKind())
 
247
                {
 
248
                case AttributeInfo::Integer:
 
249
                    PluginGetAttrInt(m_Info, it->GetName(), &v);
 
250
                    sprintf(b, "%s=%d", it->GetName(), v);
 
251
                    break;
 
252
                case AttributeInfo::Float:
 
253
                    PluginGetAttrFloat(m_Info, it->GetName(), &f);
 
254
                    sprintf(b, "%s=%f", it->GetName(), f);
 
255
                    break;
 
256
                default:
 
257
                    ;
 
258
                }
 
259
                Debug printf("pass options '%s':   %s\n", it->GetName(), b);
 
260
                avoption_parse(m_pAvContext, codec->options, b);
 
261
            }
 
262
        }
 
263
#endif
 
264
        /*
 
265
         static const struct fftable {
 
266
         const char* attr;
 
267
         int flag;
 
268
         } fftab[] = {
 
269
         { ffstr_bug_old_msmpeg4, FF_BUG_OLD_MSMPEG4 },
 
270
         { ffstr_bug_xvid_ilace, FF_BUG_XVID_ILACE },
 
271
         { ffstr_bug_ump4, FF_BUG_UMP4 },
 
272
         { ffstr_bug_no_padding, FF_BUG_NO_PADDING },
 
273
         { ffstr_bug_ac_vlc, FF_BUG_AC_VLC },
 
274
         { ffstr_bug_qpel_chroma, FF_BUG_QPEL_CHROMA },
 
275
         { 0, 0 }
 
276
         };
 
277
         for (const struct fftable* p = fftab; p->attr; p++)
 
278
         {
 
279
         if (m_Info.FindAttribute(p->attr)
 
280
         && PluginGetAttrInt(m_Info, p->attr, &v) == 0 && v)
 
281
         m_pAvContext->workaround_bugs |= p->flag;
 
282
         }
 
283
         */
 
284
        if (avcodec_open(m_pAvContext, m_pAvCodec) < 0)
 
285
        {
 
286
            AVM_WRITE(m_Info.GetPrivateName(), "WARNING: FFVideoDecoder::DecodeFrame() can't open avcodec\n");
 
287
            Stop();
 
288
            return -1;
 
289
        }
 
290
    }
 
291
 
 
292
    // try using draw_horiz_band if DR1 is unsupported
 
293
    m_pAvContext->draw_horiz_band =
 
294
        (!m_bDirect && pImage && pImage->Format() == IMG_FMT_YV12
 
295
         && (m_pAvCodec->capabilities & CODEC_CAP_DRAW_HORIZ_BAND)
 
296
         && !pImage->Direction() && render) ? draw_slice : 0;
 
297
    m_pAvContext->opaque = this;
 
298
 
 
299
    Debug printf("FF: Decode start %p   pkt size: %" PRIsz "   horiz:%d\n", pImage, size, (m_pAvContext->draw_horiz_band != 0));
 
300
    m_pImg = pImage;
 
301
    m_bUsed = false;
 
302
    m_pReleased = 0;
 
303
    AVFrame pic;
 
304
    int got_picture = 0;
 
305
 
 
306
    AVPacket avpkt;
 
307
    av_init_packet(&avpkt);
 
308
    avpkt.data = (uint8_t*)src;
 
309
    avpkt.size = (int)size;
 
310
 
 
311
    int hr = avcodec_decode_video2(m_pAvContext, &pic, &got_picture, &avpkt);
 
312
    //printf("DECFF got_picture  %d  %p   del:%d  hr:%d size:%d\n", got_picture, src, m_pAvContext->delay, hr, size);
 
313
    //printf("PictType  %d\n", m_pAvContext->pict_type);
 
314
    //static int ctr=0; printf("WIDTH %dx%d  %d  r:%d\n", m_pAvContext->width, m_pAvContext->height, ctr++, m_pAvContext->pict_type);
 
315
    Debug printf("FF: Decoded used=%d  got_pic=%d   res=%d\n", m_bUsed, got_picture, hr);
 
316
    if (hr < 0)
 
317
    {
 
318
        AVM_WRITE(m_Info.GetPrivateName(), "WARNING: FFVideoDecoder::DecodeFrame() hr=%d\n", hr);
 
319
        return hr;
 
320
    }
 
321
    if (!(m_pAvContext->flags & CODEC_FLAG_TRUNCATED))
 
322
    {
 
323
        hr = (int)size;
 
324
        //m_bUsed = true;
 
325
    }
 
326
 
 
327
    if (!m_bDirect || m_bUsed)
 
328
    {
 
329
        size_t i = m_Order.size();
 
330
        int64_t timestamp;
 
331
        uint_t position;
 
332
        if (pImage)
 
333
        {
 
334
            timestamp = pImage->m_lTimestamp;
 
335
            position = pImage->m_uiPosition;
 
336
            while (i > 0)
 
337
            {
 
338
                // keep data ordered by timestamps
 
339
                if (timestamp > m_Order[i - 1].timestamp)
 
340
                    break;
 
341
                i--;
 
342
            }
 
343
        }
 
344
        else
 
345
        {
 
346
            timestamp = 0;
 
347
            position = 0;
 
348
        }
 
349
        Debug printf("FF: Insert  %" PRIsz "    %" PRId64 "   %" PRId64 "   gotpic:%d\n", i, timestamp, m_Order[i].timestamp, got_picture);
 
350
        m_Order.insert(i, fpair(timestamp, position));
 
351
 
 
352
        if (m_bDirect)
 
353
            hr |= NEXT_PICTURE;
 
354
    }
 
355
 
 
356
    Debug printf("FF: r=0x%x  sz=%" PRIsz "  %d  b:%d  img:%p  out:%p\n", hr, size, got_picture, m_bUsed, pImage, pOut);
 
357
    Debug printf("FF: frame_size %d  number %d  picnum %d\n", m_pAvContext->frame_size, m_pAvContext->frame_number, m_pAvContext->real_pict_num);
 
358
    if (!got_picture)
 
359
    {
 
360
        Debug printf("FF: NO PICTURE  released=%p\n", m_pReleased);
 
361
        if (!m_pReleased)
 
362
            return hr | NO_PICTURE;
 
363
        // let's fake got_picture;
 
364
        if (!pic.opaque) {
 
365
            pic.type = FF_BUFFER_TYPE_USER;
 
366
            pic.opaque = m_pReleased;
 
367
        }
 
368
        got_picture = true;
 
369
    }
 
370
 
 
371
    //printf("CONTEXT %d  %x  %.4s\n", got_picture, m_pAvContext->pix_fmt, (char*)&imfmt);
 
372
 
 
373
    if (render && pImage && got_picture && !m_bDirect
 
374
        && !m_pAvContext->draw_horiz_band)
 
375
    {
 
376
        int imfmt = 0;
 
377
        Debug printf("PIXFMPT %d\n", m_pAvContext->pix_fmt);
 
378
        switch (m_pAvContext->pix_fmt)
 
379
        {
 
380
        case PIX_FMT_BGR24: imfmt = IMG_FMT_BGR24; break;
 
381
        case PIX_FMT_RGBA: imfmt = IMG_FMT_BGR32; break;
 
382
        case PIX_FMT_YUYV422: imfmt = IMG_FMT_YUY2; break;
 
383
        case PIX_FMT_YUV410P: imfmt = IMG_FMT_I410; break;
 
384
        case PIX_FMT_YUV411P: imfmt = IMG_FMT_I411; break;
 
385
        case PIX_FMT_YUV420P: imfmt = IMG_FMT_I420; break;
 
386
        case PIX_FMT_YUVJ420P: imfmt = IMG_FMT_I420; break; // strange
 
387
        case PIX_FMT_YUV422P: imfmt = IMG_FMT_I422; break;
 
388
        case PIX_FMT_YUV444P: imfmt = IMG_FMT_I444; break;
 
389
        default: break;
 
390
        }
 
391
        if (imfmt) {
 
392
            BitmapInfo bi(m_Dest);
 
393
            bi.SetSpace(imfmt);
 
394
            //bi.Print();
 
395
            //printf("FFMPEG SETSPACE\n"); pImage->GetFmt()->Print(); bi.Print();
 
396
            //printf("LINE %d %d %d\n", pic.linesize[0], pic.linesize[1], pic.linesize[2]);
 
397
            //printf("LINE %p %p %p\n", pic.data[0], pic.data[1], pic.data[2]);
 
398
            CImage ci(&bi, const_cast<const uint8_t**>(pic.data), pic.linesize, false);
 
399
            pImage->Convert(&ci);
 
400
            //printf("xxx %p\n", m_AvPicture.data[0]);
 
401
            //memcpy(pImage->Data(), pic.data[0], 320 * 150);
 
402
        } else {
 
403
            AVM_WRITE(m_Info.GetPrivateName(), "Unsupported colorspace: %d, FIXME\n", m_pAvContext->pix_fmt);
 
404
            pImage->Clear();
 
405
        }
 
406
    }
 
407
 
 
408
    //printf("SWAP  %lld  %lld\n", m_Order.front().timestamp, pImage->m_lTimestamp);
 
409
    //printf("SWAP  %d  %d\n", m_Order.front().position, pImage->m_uiPosition);
 
410
    //printf("P   %d    %lld\n", p, m_Order[0].timestamp, m_Order.size());
 
411
 
 
412
    Debug printf("FF: release:%p out:%p  tuc:%d(%d/%d)\n", m_pReleased, pOut, pic.type, FF_BUFFER_TYPE_USER, FF_BUFFER_TYPE_COPY);
 
413
#if 1
 
414
    if (pOut && pic.opaque &&
 
415
        ((pic.type == FF_BUFFER_TYPE_USER)
 
416
         || (pic.type == FF_BUFFER_TYPE_COPY)))
 
417
    {
 
418
        *pOut = (CImage*) pic.opaque;
 
419
        (*pOut)->m_lTimestamp = m_Order[0].timestamp;
 
420
        (*pOut)->m_uiPosition = m_Order[0].position;
 
421
    }
 
422
    else if (pImage)
 
423
    {
 
424
        pImage->m_lTimestamp = m_Order[0].timestamp;
 
425
        pImage->m_uiPosition = m_Order[0].position;
 
426
    }
 
427
#endif
 
428
    m_Order.pop();
 
429
 
 
430
    //printf("OUT %d %p\n", got_picture, *pOut);
 
431
 
 
432
    FFTIMING(ftm += avm_get_time_diff(avm_get_time_us(), ts));
 
433
    Debug printf("FF: pictype %d time:%f  c:%d  d:%d %" PRId64 "    %p\n", pic.pict_type, (double) pic.pts / 1000000.,
 
434
                 pic.coded_picture_number, pic.display_picture_number, pImage->m_lTimestamp, pic.opaque);
 
435
    //pImage->m_lTimestamp = pic.pts / (double) AV_TIME_BASE;
 
436
    m_bFlushed = false;
 
437
    return hr;
 
438
}
 
439
 
 
440
int FFVideoDecoder::SetDestFmt(int bits, fourcc_t csp)
 
441
{
 
442
    if (!CImage::Supported(csp, bits) || csp != fccYV12)
 
443
        return -1;
 
444
 
 
445
    Restart();
 
446
    return 0;
 
447
}
 
448
 
 
449
int FFVideoDecoder::Stop()
 
450
{
 
451
    if (m_pAvContext)
 
452
    {
 
453
        avcodec_close(m_pAvContext);
 
454
        free(m_pAvContext);
 
455
        m_pAvContext = 0;
 
456
    }
 
457
    return 0;
 
458
}
 
459
 
 
460
const avm::vector<AttributeInfo>& FFVideoDecoder::GetAttrs() const
 
461
{
 
462
    return m_Info.decoder_info;
 
463
}
 
464
 
 
465
int FFVideoDecoder::GetValue(const char* name, int* value) const
 
466
{
 
467
    return PluginGetAttrInt(m_Info, name, value);
 
468
}
 
469
int FFVideoDecoder::SetValue(const char* name, int value)
 
470
{
 
471
    int r = PluginSetAttrInt(m_Info, name, value);
 
472
    m_bRestart = (r == 0);
 
473
    return r;
 
474
}
 
475
 
 
476
AVM_END_NAMESPACE;