summaryrefslogtreecommitdiff
path: root/ffmpeg-fas
diff options
context:
space:
mode:
authorComment <tim@gray.(none)>2013-05-20 22:42:45 +0100
committerComment <tim@gray.(none)>2013-05-20 22:42:45 +0100
commit1099cec06b35a5b401a30fed9a13a5b448834b7e (patch)
treedd0a904d7a4114069d289056b5d71283f15ea2cc /ffmpeg-fas
parent7a3d7d2779a99fda5362ca341c965ddff826b2b7 (diff)
ffmpeg-fas
Diffstat (limited to 'ffmpeg-fas')
-rw-r--r--ffmpeg-fas/COPYING.GPL339
-rw-r--r--ffmpeg-fas/COPYING.LGPL504
-rw-r--r--ffmpeg-fas/README14
-rwxr-xr-xffmpeg-fas/build.sh9
-rw-r--r--ffmpeg-fas/ffmpeg_fas.c801
-rw-r--r--ffmpeg-fas/ffmpeg_fas.h109
-rw-r--r--ffmpeg-fas/private_errors.h28
-rw-r--r--ffmpeg-fas/seek_indices.c319
-rw-r--r--ffmpeg-fas/seek_indices.h94
-rwxr-xr-xffmpeg-fas/test/build.sh7
-rw-r--r--ffmpeg-fas/test/dump_frames.c67
-rw-r--r--ffmpeg-fas/test/dump_keyframes.c76
-rw-r--r--ffmpeg-fas/test/external_seek_test.c172
-rw-r--r--ffmpeg-fas/test/generate_seek_table.c209
-rw-r--r--ffmpeg-fas/test/movie_info.c81
-rwxr-xr-xffmpeg-fas/test/run_test.py56
-rw-r--r--ffmpeg-fas/test/seek_test.c162
-rw-r--r--ffmpeg-fas/test/show_seek_table.c59
-rw-r--r--ffmpeg-fas/test/test_support.h67
19 files changed, 3173 insertions, 0 deletions
diff --git a/ffmpeg-fas/COPYING.GPL b/ffmpeg-fas/COPYING.GPL
new file mode 100644
index 0000000..d159169
--- /dev/null
+++ b/ffmpeg-fas/COPYING.GPL
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program 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 of the License, or
+ (at your option) any later version.
+
+ This program 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 this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/ffmpeg-fas/COPYING.LGPL b/ffmpeg-fas/COPYING.LGPL
new file mode 100644
index 0000000..00b4fed
--- /dev/null
+++ b/ffmpeg-fas/COPYING.LGPL
@@ -0,0 +1,504 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/ffmpeg-fas/README b/ffmpeg-fas/README
new file mode 100644
index 0000000..6cb5e32
--- /dev/null
+++ b/ffmpeg-fas/README
@@ -0,0 +1,14 @@
+The frame-accurate seek library extension to ffmpeg requires ffmpeg.
+Getting the most recent version of ffmpeg and building it from source is
+recommended:
+
+svn checkout svn://svn.mplayerhq.hu/ffmpeg/trunk ffmpeg
+
+The test/example build script requires ffmpeg be checked out (or symlinked)
+from the base directory.
+
+Features:
+1) Simplified interface for video processing
+2) Frame-accurate seeking using a seek-table
+3) Online creation of a seek-table through normal decoding
+4) Saving and loading of seek-tables. \ No newline at end of file
diff --git a/ffmpeg-fas/build.sh b/ffmpeg-fas/build.sh
new file mode 100755
index 0000000..c27bc85
--- /dev/null
+++ b/ffmpeg-fas/build.sh
@@ -0,0 +1,9 @@
+cd `dirname $0`
+FFMPEG_BASEDIR=./ffmpeg/
+
+rm -rf lib
+mkdir lib
+
+gcc ffmpeg_fas.c seek_indices.c -Iffmpeg ffmpeg/libavformat/libavformat.a ffmpeg/libavcodec/libavcodec.a ffmpeg/libavutil/libavutil.a -O2 -shared -o lib/libffmpeg_fas.so
+gcc -c ffmpeg_fas.c seek_indices.c -O2 -I$FFMPEG_BASEDIR
+ar rc lib/libffmpeg_fas.a ffmpeg_fas.o seek_indices.o
diff --git a/ffmpeg-fas/ffmpeg_fas.c b/ffmpeg-fas/ffmpeg_fas.c
new file mode 100644
index 0000000..38a614c
--- /dev/null
+++ b/ffmpeg-fas/ffmpeg_fas.c
@@ -0,0 +1,801 @@
+/*****************************************************************************
+ * Copyright 2008. Pittsburgh Pattern Recognition, Inc.
+ *
+ * This file is part of the Frame Accurate Seeking extension library to
+ * ffmpeg (ffmpeg-fas).
+ *
+ * ffmpeg-fas is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * The ffmpeg-fas library 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 Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the ffmpeg-fas library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ ******************************************************************************/
+
+#include "ffmpeg_fas.h"
+#include "libavformat/avformat.h"
+#include "libavcodec/avcodec.h"
+#include "seek_indices.h"
+#include "private_errors.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+
+#define FIRST_FRAME_INDEX 0
+#define NUM_POSSIBLE_ERRORS 9
+
+/**** Private Types ***********************************************************/
+
+typedef struct fas_context_struct {
+ fas_boolean_type is_video_active;
+ fas_boolean_type is_frame_available;
+
+ int current_frame_index;
+
+ seek_table_type seek_table;
+
+ /* ffmpeg */
+ AVFormatContext *format_context;
+ AVCodecContext *codec_context;
+ int stream_idx;
+
+ AVFrame *frame_buffer; // internal buffer
+
+ AVFrame *rgb_frame_buffer; // extra AVFrames (for color conversion)
+ uint8_t *rgb_buffer; // actual data buffer for rgb_frame_buffer (needs to be freed seperately)
+ fas_boolean_type rgb_already_converted; // color_convert(frame_buffer) == rgb_frame_buffer (so we don't need to repeat conversions)
+
+ AVFrame *gray8_frame_buffer;
+ uint8_t *gray8_buffer;
+ fas_boolean_type gray8_already_converted;
+
+ int64_t current_dts; // decoding timestamp of the most recently parsed packet
+ int64_t previous_dts; // for previous packet (always use previous packet for seek_table (workaround))
+ int64_t keyframe_packet_dts; // dts of most recent keyframe packet
+ int64_t first_dts; // for very first packet (needed in seek, for first keyframe)
+
+} fas_context_type;
+
+static char* invalid_error_code = "not a valid error code";
+static char *gbl_error_strings[NUM_POSSIBLE_ERRORS] =
+{
+ "fas_success",
+ "fas_failure",
+ "fas_invalid_argument",
+ "fas_out_of_memory",
+ "fas_unsupported_format",
+ "fas_unsupported_codec",
+ "fas_no_more_frames",
+ "fas_decoding_error",
+ "fas_seek_error"
+};
+
+char* fas_error_message(fas_error_type error)
+{
+ if ((error < 0) || (error >= NUM_POSSIBLE_ERRORS))
+ return invalid_error_code;
+
+ return gbl_error_strings[error];
+}
+
+static void private_show_warning (const char *message);
+static fas_error_type private_show_error (const char *message, fas_error_type error);
+static fas_error_type private_convert_to_rgb (fas_context_ref_type ctx);
+static fas_error_type private_seek_to_nearest_key (fas_context_ref_type context, int target_index, int offset);
+fas_error_type private_complete_seek_table (fas_context_ref_type context);
+
+
+void fas_set_logging (fas_boolean_type logging)
+{
+ if (logging == FAS_TRUE)
+ {
+ SHOW_ERROR_MESSAGES = 1;
+ SHOW_WARNING_MESSAGES = 1;
+ av_log_level = AV_LOG_INFO;
+ }
+ else
+ {
+ SHOW_ERROR_MESSAGES = 0;
+ SHOW_WARNING_MESSAGES = 0;
+ av_log_level = AV_LOG_QUIET;
+ }
+}
+
+void fas_initialize (fas_boolean_type logging)
+{
+ fas_set_logging(logging);
+ av_register_all();
+
+ return;
+}
+
+/* fas_open_video */
+
+fas_error_type fas_open_video (fas_context_ref_type *context_ptr, char *file_path)
+{
+ if (NULL == context_ptr)
+ return private_show_error ("NULL context pointer provided", FAS_INVALID_ARGUMENT);
+
+ // seek_error_type seek_error;
+ fas_context_ref_type fas_context;
+
+ *context_ptr = NULL; // set returned context to NULL in case of error
+
+ fas_context = (fas_context_ref_type)malloc (sizeof (fas_context_type));
+ memset(fas_context, 0, sizeof(fas_context_type));
+
+ if (NULL == fas_context)
+ return private_show_error ("unable to allocate buffer", FAS_OUT_OF_MEMORY);
+
+ fas_context->is_video_active = FAS_TRUE;
+ fas_context->is_frame_available = FAS_TRUE;
+ fas_context->current_frame_index = FIRST_FRAME_INDEX - 1;
+ fas_context->current_dts = AV_NOPTS_VALUE;
+ fas_context->previous_dts = AV_NOPTS_VALUE;
+ fas_context->keyframe_packet_dts = AV_NOPTS_VALUE;
+ fas_context->first_dts = AV_NOPTS_VALUE;
+
+ fas_context->seek_table = seek_init_table (-1); /* default starting size */
+
+ if (av_open_input_file ( &(fas_context->format_context), file_path, NULL, 0, NULL ) != 0)
+ {
+ fas_close_video(fas_context);
+ return private_show_error ("failure to open file", FAS_UNSUPPORTED_FORMAT);
+ }
+
+ if (av_find_stream_info (fas_context->format_context) < 0)
+ {
+ fas_close_video(fas_context);
+ return private_show_error ("could not extract stream information", FAS_UNSUPPORTED_FORMAT);
+ }
+
+ if (SHOW_WARNING_MESSAGES)
+ dump_format(fas_context->format_context, 0, file_path, 0);
+
+ int stream_idx;
+ for (stream_idx = 0; stream_idx < fas_context->format_context->nb_streams; stream_idx++)
+ {
+ if (fas_context->format_context->streams[stream_idx]->codec->codec_type == CODEC_TYPE_VIDEO)
+ {
+ fas_context->stream_idx = stream_idx;
+ fas_context->codec_context = fas_context->format_context->streams[stream_idx]->codec;
+ break;
+ }
+ }
+
+ if (fas_context->codec_context == 0)
+ {
+ fas_close_video(fas_context);
+ return private_show_error ("failure to find a video stream", FAS_UNSUPPORTED_FORMAT);
+ }
+
+ AVCodec *codec = avcodec_find_decoder (fas_context->codec_context->codec_id);
+
+ if (!codec)
+ {
+ fas_context->codec_context = 0;
+ fas_close_video(fas_context);
+ return private_show_error("failed to find correct video codec", FAS_UNSUPPORTED_CODEC);
+ }
+
+ if (avcodec_open (fas_context->codec_context, codec) < 0)
+ {
+ fas_context->codec_context = 0;
+ fas_close_video(fas_context);
+ return private_show_error ("failed to open codec", FAS_UNSUPPORTED_CODEC);
+ }
+
+ fas_context->frame_buffer = avcodec_alloc_frame ();
+ if (fas_context->frame_buffer == NULL)
+ {
+ fas_close_video(fas_context);
+ return private_show_error ("failed to allocate frame buffer", FAS_OUT_OF_MEMORY);
+ }
+
+ fas_context->rgb_frame_buffer = avcodec_alloc_frame ();
+ if (fas_context->rgb_frame_buffer == NULL)
+ {
+ fas_close_video(fas_context);
+ return private_show_error ("failed to allocate rgb frame buffer", FAS_OUT_OF_MEMORY);
+ }
+
+ fas_context->gray8_frame_buffer = avcodec_alloc_frame ();
+ if (fas_context->gray8_frame_buffer == NULL)
+ {
+ fas_close_video(fas_context);
+ return private_show_error ("failed to allocate gray8 frame buffer", FAS_OUT_OF_MEMORY);
+ }
+
+ fas_context->rgb_buffer = 0;
+ fas_context->gray8_buffer = 0;
+ fas_context->rgb_already_converted = FAS_FALSE;
+ fas_context->gray8_already_converted = FAS_FALSE;
+
+ *context_ptr = fas_context;
+
+
+ if (FAS_SUCCESS != fas_step_forward(*context_ptr))
+ return private_show_error ("failure decoding first frame", FAS_NO_MORE_FRAMES);
+
+ if (!fas_frame_available(*context_ptr))
+ return private_show_error ("couldn't find a first frame (no valid frames in video stream)", FAS_NO_MORE_FRAMES);
+
+
+
+ return FAS_SUCCESS;
+}
+
+/* fas_close_video */
+fas_error_type fas_close_video (fas_context_ref_type context)
+{
+ if (NULL == context)
+ return private_show_error ("NULL context provided for fas_close_video()", FAS_INVALID_ARGUMENT);
+
+ if (!(context->is_video_active))
+ {
+ private_show_warning ("Redundant attempt to close an inactive video");
+ return FAS_SUCCESS;
+ }
+
+ if (context->codec_context)
+ if (avcodec_find_decoder (context->codec_context->codec_id))
+ avcodec_close(context->codec_context);
+
+ if (context->format_context)
+ av_close_input_file (context->format_context);
+
+ if (context->rgb_frame_buffer)
+ av_free (context->rgb_frame_buffer);
+
+ if (context->gray8_frame_buffer)
+ av_free (context->gray8_frame_buffer);
+
+ if (context->rgb_buffer)
+ av_free(context->rgb_buffer);
+
+ if (context->gray8_buffer)
+ av_free(context->gray8_buffer);
+
+ if (context->frame_buffer)
+ av_free (context->frame_buffer);
+
+ seek_release_table (&(context->seek_table));
+
+ context->is_video_active = FAS_FALSE;
+
+ free (context);
+
+ return FAS_SUCCESS;
+}
+
+
+/* fas_step_forward */
+fas_error_type fas_step_forward (fas_context_ref_type context)
+{
+ if ((NULL == context) || (FAS_TRUE != context->is_video_active)) {
+ return private_show_error ("invalid or unopened context", FAS_INVALID_ARGUMENT);
+ }
+
+ if (!context->is_frame_available)
+ {
+ private_show_warning ("tried to advance after end of frames");
+ return FAS_SUCCESS;
+ }
+
+ context->current_frame_index++;
+
+ AVPacket packet;
+ while (FAS_TRUE)
+ {
+ if (av_read_frame(context->format_context, &packet) < 0)
+ {
+ /* finished */
+ context->is_frame_available = FAS_FALSE;
+ context->seek_table.completed = seek_true;
+ return FAS_SUCCESS;
+ }
+
+ int frameFinished;
+ if (packet.stream_index == context->stream_idx)
+ {
+ context->previous_dts = context->current_dts;
+ context->current_dts = packet.dts;
+
+ /* seek support: set first_dts */
+ if (context->first_dts == AV_NOPTS_VALUE)
+ context->first_dts = packet.dts;
+
+ /* seek support: set key-packet info to previous packet's dts, when possible */
+ /* note this -1 approach to setting the packet is a workaround for a common failure. setting
+ to 0 would work just incur a huge penalty in videos that needed -1. Might be worth testing.
+ */
+ if (packet.flags & PKT_FLAG_KEY)
+ {
+ //fprintf(stderr, "Packet: (F:%d %lld %lld)\n", context->current_frame_index, packet.pts, packet.dts);
+
+ if (context->previous_dts == AV_NOPTS_VALUE)
+ context->keyframe_packet_dts = packet.dts;
+ else
+ context->keyframe_packet_dts = context->previous_dts;
+ }
+
+ avcodec_decode_video(context->codec_context, context->frame_buffer, &frameFinished,
+ packet.data, packet.size);
+
+ if (frameFinished)
+ {
+ /* seek support: (try to) add entry to seek_table */
+ if (context->frame_buffer->key_frame)
+ {
+ // fprintf(stderr, "Frame : (PXX F%d: %lld %lld)\n", context->current_frame_index, packet.pts, packet.dts);
+
+ seek_entry_type entry;
+ entry.display_index = context->current_frame_index;
+ entry.first_packet_dts = context->keyframe_packet_dts;
+ entry.last_packet_dts = packet.dts;
+
+ if (fas_get_frame_index(context) == FIRST_FRAME_INDEX)
+ entry.first_packet_dts = context->first_dts;
+
+ seek_append_table_entry(&context->seek_table, entry);
+ }
+
+ if (context->current_frame_index - FIRST_FRAME_INDEX + 1 > context->seek_table.num_frames)
+ context->seek_table.num_frames = context->current_frame_index - FIRST_FRAME_INDEX + 1;
+
+ break;
+ }
+ }
+
+ av_free_packet(&packet);
+ }
+
+ context->rgb_already_converted = FAS_FALSE;
+ context->gray8_already_converted = FAS_FALSE;
+ av_free_packet(&packet);
+ return FAS_SUCCESS;
+}
+
+/* fas_get_frame_index */
+
+int fas_get_frame_index (fas_context_ref_type context)
+{
+ if (NULL == context)
+ return private_show_error ("NULL context provided for fas_get_frame_index()", FAS_INVALID_ARGUMENT);
+
+ if (FAS_TRUE != context->is_video_active)
+ return private_show_error ("No video is open for fas_get_frame_index()", FAS_INVALID_ARGUMENT);
+
+ return context->current_frame_index;
+}
+
+
+/* fas_get_frame */
+
+fas_error_type fas_get_frame (fas_context_ref_type context, fas_raw_image_type *image_ptr)
+{
+ int buffer_size;
+ fas_error_type fas_error;
+
+ if (NULL == context || FAS_FALSE == context->is_video_active)
+ return private_show_error ("null context or inactive video", FAS_INVALID_ARGUMENT);
+
+ if (NULL == image_ptr)
+ return private_show_error ("null image_ptr on get_frame", FAS_INVALID_ARGUMENT);
+
+ if (!fas_frame_available(context))
+ return private_show_error ("no frame available for extraction", FAS_NO_MORE_FRAMES);
+
+ memset (image_ptr, 0, sizeof (fas_raw_image_type));
+
+ buffer_size = context->codec_context->width * context->codec_context->height * 3;
+
+ image_ptr->data = (unsigned char *)malloc (buffer_size);
+ if (NULL == image_ptr->data)
+ return private_show_error ("unable to allocate space for RGB image", FAS_OUT_OF_MEMORY);
+
+ image_ptr->color_space = FAS_RGB24;
+ image_ptr->width = context->codec_context->width;
+ image_ptr->height = context->codec_context->height;
+ image_ptr->bytes_per_line = context->codec_context->width * 3;
+
+
+ fas_error = private_convert_to_rgb(context);
+
+ int j;
+ unsigned char *from;
+ unsigned char *to;
+ for (j=0;j<context->codec_context->height; j++)
+ {
+ from = context->rgb_frame_buffer->data[0] + j*context->rgb_frame_buffer->linesize[0];
+ to = image_ptr->data + j*image_ptr->bytes_per_line;
+
+ memcpy(to, from, context->codec_context->width *3);
+ }
+
+ if (FAS_SUCCESS != fas_error)
+ return private_show_error ("unable to convert image to RGB", FAS_FAILURE);
+
+ return FAS_SUCCESS;
+}
+
+/* fas_free_frame */
+
+void fas_free_frame (fas_raw_image_type image)
+{
+ if (NULL == image.data)
+ return;
+
+ free (image.data);
+
+ return;
+}
+
+/* fas_get_seek_table */
+seek_table_type fas_get_seek_table (fas_context_ref_type context)
+{
+ seek_table_type null_table;
+
+ null_table.array = NULL;
+ null_table.completed = seek_false;
+ null_table.num_frames = -1;
+ null_table.num_entries = 0;
+ null_table.allocated_size = 0;
+
+ if (NULL == context || FAS_FALSE == context->is_video_active)
+ return null_table;
+
+ return context->seek_table;
+}
+
+/* fas_put_seek_table */
+fas_error_type fas_put_seek_table (fas_context_ref_type context, seek_table_type table)
+{
+ if (NULL == context || FAS_FALSE == context->is_video_active)
+ return private_show_error ("null context or inactive video", FAS_INVALID_ARGUMENT);
+
+ seek_release_table (&context->seek_table);
+ context->seek_table = seek_copy_table(table);
+
+ return FAS_SUCCESS;
+}
+
+/* private_complete_seek_table */
+fas_error_type private_complete_seek_table (fas_context_ref_type context)
+{
+ if ((NULL == context) || (FAS_FALSE == context->is_video_active))
+ return private_show_error ("invalid or unopened context", FAS_INVALID_ARGUMENT);
+
+ if (context->seek_table.completed)
+ return FAS_SUCCESS;
+
+ fas_error_type fas_error = fas_seek_to_nearest_key (context, context->seek_table.num_frames + FIRST_FRAME_INDEX - 1);
+ if (FAS_SUCCESS != fas_error)
+ return private_show_error("failed when trying to complete seek table (1) (first frame not labeled keyframe?)", fas_error);
+
+ while (fas_frame_available(context))
+ {
+ // printf("%d\n", context->seek_table.num_frames);
+ fas_step_forward(context);
+ }
+
+ if (!context->seek_table.completed)
+ return private_show_error("failed when trying to complete seek table (2)", FAS_SEEK_ERROR);
+
+ return FAS_SUCCESS;
+}
+
+/* fas_seek_to_frame */
+fas_error_type fas_seek_to_frame (fas_context_ref_type context, int target_index)
+{
+
+ fas_error_type fas_error;
+
+ if ((NULL == context) || (FAS_FALSE == context->is_video_active))
+ return private_show_error ("invalid or unopened context", FAS_INVALID_ARGUMENT);
+
+ // printf("seeking to %d (from %d)!\n", target_index, context->current_frame_index);
+ if (target_index == context->current_frame_index)
+ return FAS_SUCCESS;
+
+ fas_error = fas_seek_to_nearest_key (context, target_index);
+
+ if (fas_error != FAS_SUCCESS)
+ return private_show_error ("error advancing to key frame before seek", fas_error);
+
+ if (fas_get_frame_index(context) > target_index)
+ return private_show_error ("error advancing to key frame before seek (index isn't right)", fas_error);
+
+ while (fas_get_frame_index(context) < target_index)
+ {
+ if (fas_frame_available(context))
+ fas_step_forward(context);
+ else
+ return private_show_error ("error advancing to request frame (probably out of range)", FAS_SEEK_ERROR);
+ }
+
+
+ return FAS_SUCCESS;
+}
+
+/* fas_seek_to_nearest_key */
+
+fas_error_type fas_seek_to_nearest_key (fas_context_ref_type context, int target_index)
+{
+ return private_seek_to_nearest_key(context, target_index,0);
+}
+
+/* private_seek_to_nearest_key */
+
+fas_error_type private_seek_to_nearest_key (fas_context_ref_type context, int target_index, int offset)
+{
+ if ((NULL == context) || (FAS_TRUE != context->is_video_active))
+ return private_show_error ("invalid or unopened context", FAS_INVALID_ARGUMENT);
+
+ // printf("HERE: from: %d to: %d offset: %d\n", context->current_frame_index, target_index, offset);
+ fas_error_type fas_error;
+ seek_entry_type seek_entry;
+ seek_error_type seek_error = seek_get_nearest_entry (&(context->seek_table), &seek_entry, target_index, offset);
+
+ if (seek_error != seek_no_error)
+ return private_show_error ("error while searching seek table", FAS_SEEK_ERROR);
+
+ if (seek_entry.display_index == context->current_frame_index)
+ return FAS_SUCCESS;
+
+ // printf("HERE: from: %d to: %d (%d) offset: %d\n", context->current_frame_index, target_index, seek_entry.display_index, offset);
+ // printf("trying to seek to %d (%lld->%lld)\n", seek_entry.display_index, seek_entry.first_packet_dts, seek_entry.last_packet_dts);
+
+ // if something goes terribly wrong, return bad current_frame_index
+ context->current_frame_index = -2;
+ context->is_frame_available = FAS_TRUE;
+
+ int flags = 0;
+ if (seek_entry.first_packet_dts <= context->current_dts)
+ flags = AVSEEK_FLAG_BACKWARD;
+
+ // printf("av_seek_frame: %lld\n", seek_entry.first_packet_dts);
+ if (av_seek_frame(context->format_context, context->stream_idx, seek_entry.first_packet_dts, flags) < 0)
+ return private_show_error("seek to keyframe failed", FAS_SEEK_ERROR);
+
+
+ avcodec_flush_buffers (context->codec_context);
+
+ fas_error = fas_step_forward (context);
+
+ if (fas_error != FAS_SUCCESS || !context->is_frame_available)
+ {
+ // something bad has happened, try previous keyframe
+ private_show_warning("processing of seeked keyframe failed, trying previous keyframe");
+ return private_seek_to_nearest_key(context, target_index, offset + 1);
+ }
+
+ while (context->current_dts < seek_entry.last_packet_dts)
+ {
+ //printf("frame-times: current: %lld target: %lld is_key: %d\n", context->current_dts, seek_entry.last_packet_dts, context->frame_buffer->key_frame);
+ fas_error = fas_step_forward(context);
+ if (fas_error != FAS_SUCCESS)
+ return private_show_error ("unable to process up to target frame (fas_seek_to_frame)", fas_error);
+ }
+
+ // printf("keyframe vitals: %d looking_for: %lld at: %lld\n", seek_entry.display_index, seek_entry.last_packet_dts, context->current_dts);
+ if (context->current_dts != seek_entry.last_packet_dts)
+ {
+ /* seek to last key-frame, but look for this one */
+ private_show_warning("missed keyframe, trying previous keyframe");
+ return private_seek_to_nearest_key(context, target_index, offset + 1);
+ }
+
+ /* Ideally, we could just check if the frame decoded is of the correct time stamp... but... we need several ugly workarounds:
+
+ 1) Some videos have bad keyframes that don't get decoded properly. In this cases, we need to go back a keyframe.
+
+ 2) Other times, none of the frames are labeled keyframes. In these cases, we need to allow seeking to frame 0
+ even when it's not labeled as a keyframe. Messy set of conditions.
+ */
+
+ if ((!context->frame_buffer->key_frame) && (seek_entry.display_index != 0))
+ {
+ private_show_warning("found keyframe, but not labeled as keyframe, so trying previous keyframe.");
+ /* seek & look for previous keyframe */
+ /* REMOVE FROM TABLE? */
+ return private_seek_to_nearest_key(context, seek_entry.display_index - 1, 0);
+ }
+
+ context->current_frame_index = seek_entry.display_index;
+
+ return FAS_SUCCESS;
+}
+
+/* fas_get_frame_count */
+
+int fas_get_frame_count_fast (fas_context_ref_type context)
+{
+
+ if (NULL == context || FAS_FALSE == context->is_video_active)
+ {
+ private_show_error ("NULL or invalid context", FAS_INVALID_ARGUMENT);
+ return -1;
+ }
+
+ if (context->seek_table.completed == seek_true)
+ return context->seek_table.num_frames;
+
+ return -1;
+}
+
+int fas_get_frame_count (fas_context_ref_type context)
+{
+ int fast = fas_get_frame_count_fast(context);
+ if (fast >= 0)
+ return fast;
+
+ int current_frame = fas_get_frame_index(context);
+
+ fas_error_type fas_error;
+
+ fas_error = private_complete_seek_table(context);
+ if (FAS_SUCCESS != fas_error)
+ {
+ private_show_error("failed in get_frame_count trying to complete the seek table", fas_error);
+ return -1;
+ }
+
+ // seek_show_raw_table(stderr, context->seek_table);
+
+ fas_error = fas_seek_to_frame(context, current_frame);
+ if (FAS_SUCCESS != fas_error)
+ {
+ private_show_error("failed in get_frame_count when trying to seek back to original location", fas_error);
+ return -1;
+ }
+
+ fast = fas_get_frame_count_fast(context);
+ if (fast < 0)
+ private_show_warning("get_frame_count failed");
+
+ return fast;
+}
+
+/* fas_frame_available */
+
+fas_boolean_type fas_frame_available (fas_context_ref_type context)
+{
+ if (NULL == context)
+ {
+ private_show_error ("NULL context provided for fas_get_frame_index()", FAS_INVALID_ARGUMENT);
+ return FAS_FALSE;
+ }
+
+ if (!context->is_video_active)
+ return FAS_FALSE;
+
+ return context->is_frame_available;
+}
+
+
+/* private_show_error */
+
+static fas_error_type private_show_error (const char *message, fas_error_type error)
+{
+ if (SHOW_ERROR_MESSAGES)
+ fprintf (stderr, " ===> ffmpeg_fas: %s\n", message);
+ return error;
+}
+
+static void private_show_warning (const char *message)
+{
+ if (SHOW_WARNING_MESSAGES)
+ fprintf (stderr, " ---- ffmpeg_fas: %s\n", message);
+ return;
+}
+
+
+/* private_convert_to_rgb */
+
+fas_error_type private_convert_to_rgb (fas_context_ref_type ctx)
+{
+ if (ctx->rgb_already_converted)
+ return FAS_SUCCESS;
+
+ if (ctx->rgb_buffer == 0)
+ {
+ int numBytes = avpicture_get_size(PIX_FMT_RGB24, ctx->codec_context->width,
+ ctx->codec_context->height);
+ ctx->rgb_buffer = (uint8_t *) av_malloc(numBytes*sizeof(uint8_t));
+ avpicture_fill((AVPicture *) ctx->rgb_frame_buffer, ctx->rgb_buffer, PIX_FMT_RGB24,
+ ctx->codec_context->width, ctx->codec_context->height);
+ }
+
+ if (img_convert((AVPicture *) ctx->rgb_frame_buffer, PIX_FMT_RGB24, (AVPicture *) ctx->frame_buffer,
+ ctx->codec_context->pix_fmt,
+ ctx->codec_context->width, ctx->codec_context->height) < 0)
+ private_show_error("error converting to rgb", FAS_DECODING_ERROR);
+
+ ctx->rgb_already_converted = FAS_TRUE;
+
+ return FAS_SUCCESS;
+}
+
+
+/* private_convert_to_gray8 */
+
+fas_error_type private_convert_to_gray8 (fas_context_ref_type ctx)
+{
+ if (ctx->gray8_already_converted)
+ return FAS_SUCCESS;
+
+ if (ctx->gray8_buffer == 0)
+ {
+ int numBytes = avpicture_get_size(PIX_FMT_GRAY8, ctx->codec_context->width,
+ ctx->codec_context->height);
+ ctx->gray8_buffer = (uint8_t *) av_malloc(numBytes*sizeof(uint8_t));
+ avpicture_fill((AVPicture *) ctx->gray8_frame_buffer, ctx->gray8_buffer, PIX_FMT_GRAY8,
+ ctx->codec_context->width, ctx->codec_context->height);
+ }
+
+ if (img_convert((AVPicture *) ctx->gray8_frame_buffer, PIX_FMT_GRAY8, (AVPicture *) ctx->frame_buffer,
+ ctx->codec_context->pix_fmt,
+ ctx->codec_context->width, ctx->codec_context->height) < 0)
+ private_show_error("error converting to gray8", FAS_DECODING_ERROR);
+
+ ctx->gray8_already_converted = FAS_TRUE;
+
+ return FAS_SUCCESS;
+}
+
+int fas_get_current_width(fas_context_ref_type context)
+{
+ return context->codec_context->width;
+}
+
+int fas_get_current_height(fas_context_ref_type context)
+{
+ return context->codec_context->height;
+}
+
+fas_error_type fas_fill_gray8_ptr(fas_context_ref_type context, unsigned char *y)
+{
+ /* this conversion also seems to screw up sometimes -- pal8 -> gray8? legodragon.avi */
+ if (private_convert_to_gray8(context) != FAS_SUCCESS)
+ return FAS_FAILURE;
+
+ int width = context->codec_context->width;
+ int height = context->codec_context->height;
+ int i;
+ for (i=0;i < height; i++)
+ memcpy(y + width * i, context->gray8_frame_buffer->data[0] + context->gray8_frame_buffer->linesize[0] * i, width);
+
+ return FAS_SUCCESS;
+}
+
+fas_error_type fas_fill_420p_ptrs (fas_context_ref_type context, unsigned char *y, unsigned char *u, unsigned char *v)
+{
+ AVFrame *p = context->frame_buffer;
+
+ /* 411p to 420p conversion fails!? ... so i left this -ldb */
+ if (context->codec_context->pix_fmt != PIX_FMT_YUV420P)
+ return FAS_FAILURE;
+
+ int width = context->codec_context->width;
+ int height = context->codec_context->height;
+ int i;
+ for (i=0;i < height / 2; i++)
+ {
+ memcpy(y + width * (2*i) , p->data[0] + p->linesize[0] * (2*i) , width);
+ memcpy(y + width * (2*i + 1), p->data[0] + p->linesize[0] * (2*i + 1), width);
+ memcpy(u + width / 2 * i, p->data[1] + p->linesize[1] * i, width / 2);
+ memcpy(v + width / 2 * i, p->data[2] + p->linesize[2] * i, width / 2);
+ }
+
+ return FAS_SUCCESS;
+}
diff --git a/ffmpeg-fas/ffmpeg_fas.h b/ffmpeg-fas/ffmpeg_fas.h
new file mode 100644
index 0000000..3e8be94
--- /dev/null
+++ b/ffmpeg-fas/ffmpeg_fas.h
@@ -0,0 +1,109 @@
+/*****************************************************************************
+ * Copyright 2008. Pittsburgh Pattern Recognition, Inc.
+ *
+ * This file is part of the Frame Accurate Seeking extension library to
+ * ffmpeg (ffmpeg-fas).
+ *
+ * ffmpeg-fas is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * The ffmpeg-fas library 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 Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the ffmpeg-fas library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ ******************************************************************************/
+
+#ifndef FFMPEG_FAS_H
+#define FFMPEG_FAS_H
+
+/* If C++ then we need to __extern "C". Compiler defines __cplusplus */
+#ifdef __cplusplus
+#define __extern extern "C"
+#else
+#define __extern extern
+#endif
+
+#include "seek_indices.h"
+
+typedef enum
+{
+ FAS_GRAY8 = 1,
+ FAS_RGB24 = 2,
+ FAS_ARGB32 = 3,
+} fas_color_space_type;
+
+typedef struct
+{
+ unsigned char *data;
+ int width;
+ int height;
+ int bytes_per_line;
+ fas_color_space_type color_space;
+} fas_raw_image_type;
+
+
+/**********************************************************************
+ * Video IO Types
+ **********************************************************************/
+
+typedef struct fas_context_struct* fas_context_ref_type;
+
+typedef enum
+{
+ FAS_SUCCESS,
+ FAS_FAILURE,
+ FAS_INVALID_ARGUMENT,
+ FAS_OUT_OF_MEMORY,
+ FAS_UNSUPPORTED_FORMAT,
+ FAS_UNSUPPORTED_CODEC,
+ FAS_NO_MORE_FRAMES,
+ FAS_DECODING_ERROR,
+ FAS_SEEK_ERROR,
+} fas_error_type;
+
+typedef enum
+{
+ FAS_FALSE = 0,
+ FAS_TRUE = 1
+} fas_boolean_type;
+
+
+__extern void fas_initialize (fas_boolean_type logging);
+
+__extern fas_error_type fas_open_video (fas_context_ref_type *context_ptr, char *file_path);
+__extern fas_error_type fas_close_video (fas_context_ref_type context);
+
+__extern char* fas_error_message (fas_error_type error);
+
+__extern fas_boolean_type fas_frame_available (fas_context_ref_type context);
+__extern int fas_get_frame_index (fas_context_ref_type context);
+__extern fas_error_type fas_step_forward (fas_context_ref_type context);
+
+__extern fas_error_type fas_get_frame (fas_context_ref_type context, fas_raw_image_type *image_ptr);
+__extern void fas_free_frame (fas_raw_image_type image);
+
+__extern fas_error_type fas_seek_to_nearest_key (fas_context_ref_type context, int target_index);
+__extern fas_error_type fas_seek_to_frame (fas_context_ref_type context, int target_index);
+
+__extern int fas_get_frame_count (fas_context_ref_type context);
+__extern int fas_get_frame_count_fast (fas_context_ref_type context);
+
+__extern fas_error_type fas_put_seek_table (fas_context_ref_type context, seek_table_type table);
+__extern seek_table_type fas_get_seek_table (fas_context_ref_type context);
+
+/* will extract raw 420p if the video is in that format -- needs to be alloced ahead of time*/
+__extern fas_error_type fas_fill_420p_ptrs (fas_context_ref_type context, unsigned char *y, unsigned char *u, unsigned char *v);
+
+/* will extract gray8 data from movie (will convert to ensure you get it) -- need to be alloc'ed ahead of time*/
+__extern fas_error_type fas_fill_gray8_ptr(fas_context_ref_type context, unsigned char *y);
+
+__extern int fas_get_current_width(fas_context_ref_type context);
+__extern int fas_get_current_height(fas_context_ref_type context);
+
+#endif
diff --git a/ffmpeg-fas/private_errors.h b/ffmpeg-fas/private_errors.h
new file mode 100644
index 0000000..b68f7d2
--- /dev/null
+++ b/ffmpeg-fas/private_errors.h
@@ -0,0 +1,28 @@
+/*****************************************************************************
+ * Copyright 2008. Pittsburgh Pattern Recognition, Inc.
+ *
+ * This file is part of the Frame Accurate Seeking extension library to
+ * ffmpeg (ffmpeg-fas).
+ *
+ * ffmpeg-fas is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * The ffmpeg-fas library 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 Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the ffmpeg-fas library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ ******************************************************************************/
+
+#ifndef FAS_PRIVATE_ERROR_H
+#define FAS_PRIVATE_ERROR_H
+
+int SHOW_ERROR_MESSAGES;
+int SHOW_WARNING_MESSAGES;
+
+#endif
diff --git a/ffmpeg-fas/seek_indices.c b/ffmpeg-fas/seek_indices.c
new file mode 100644
index 0000000..63d2b23
--- /dev/null
+++ b/ffmpeg-fas/seek_indices.c
@@ -0,0 +1,319 @@
+/*****************************************************************************
+ * Copyright 2008. Pittsburgh Pattern Recognition, Inc.
+ *
+ * This file is part of the Frame Accurate Seeking extension library to
+ * ffmpeg (ffmpeg-fas).
+ *
+ * ffmpeg-fas is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * The ffmpeg-fas library 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 Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the ffmpeg-fas library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ ******************************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "seek_indices.h"
+#include "private_errors.h"
+
+/**** Defines *****************************************************************/
+
+#define DEFAULT_INITIAL_SIZE 100
+
+static seek_error_type private_show_error (const char *message, seek_error_type error);
+static seek_error_type private_resize_table (seek_table_type *table, int new_size);
+
+
+/*
+ * seek_init_table
+ */
+
+int compare_seek_tables(seek_table_type t1, seek_table_type t2)
+{
+ int i;
+
+ // printf("n_entries=(%d %d)\n", t1.num_entries, t2.num_entries);
+
+ if (t1.num_entries != t2.num_entries)
+ return 0;
+
+ if (t1.completed != t2.completed)
+ return 0;
+
+ if (t1.num_frames != t2.num_frames)
+ return 0;
+
+ for (i=0;i<t1.num_entries;i++)
+ {
+ // printf("(%d %d) (%lld %lld) (%lld %lld)\n",
+ // t1.array[i].display_index, t2.array[i].display_index,
+ // t1.array[i].decode_time, t2.array[i].decode_time,
+ // t1.array[i].display_time, t2.array[i].display_time);
+ if ((t1.array[i].display_index != t2.array[i].display_index) ||
+ (t1.array[i].last_packet_dts != t2.array[i].last_packet_dts) ||
+ (t1.array[i].first_packet_dts != t2.array[i].first_packet_dts))
+ return 0;
+ }
+
+ return 1;
+}
+
+seek_table_type seek_init_table (int initial_size)
+{
+ seek_table_type table;
+
+ if (initial_size < 0)
+ initial_size = DEFAULT_INITIAL_SIZE;
+
+ table.num_entries = 0;
+ table.num_frames = -1;
+ table.completed = seek_false;
+
+ table.array = (seek_entry_type *)malloc (initial_size * sizeof(seek_entry_type));
+
+ if (NULL == table.array)
+ table.allocated_size = 0;
+ else
+ table.allocated_size = initial_size;
+
+ return table;
+}
+
+/*
+ * seek_release_table
+ */
+
+void seek_release_table (seek_table_type *table)
+{
+ table->num_entries = 0;
+ table->num_frames = -1;
+ table->completed = seek_false;
+
+ if (NULL == table || NULL == table->array)
+ return;
+
+ free (table->array);
+ return;
+}
+
+/*
+ * seek_copy_table
+ */
+
+seek_table_type seek_copy_table (seek_table_type source)
+{
+ seek_table_type dest;
+ dest.num_entries = source.num_entries;
+ dest.num_frames = source.num_frames;
+ dest.completed = source.completed;
+
+ if (NULL == source.array)
+ {
+ dest.array = NULL;
+ dest.allocated_size = 0;
+ return dest;
+ }
+
+ dest.array = (seek_entry_type *)malloc (source.num_entries * sizeof(seek_entry_type));
+
+ if (NULL == dest.array)
+ {
+ dest.array = NULL;
+ dest.allocated_size = 0;
+ return dest;
+ }
+
+ dest.allocated_size = source.num_entries;
+
+ int i;
+ for (i=0;i<source.num_entries;i++)
+ dest.array[i] = source.array[i];
+
+ return dest;
+}
+
+seek_error_type seek_append_table_entry (seek_table_type *table, seek_entry_type entry)
+{
+
+ if (NULL == table || NULL == table->array)
+ return private_show_error("null or invalid seek table", seek_bad_argument);
+
+ if (table->num_entries != 0)
+ if (table->array[table->num_entries - 1].display_index >= entry.display_index)
+ return seek_no_error;
+
+ if (table->num_entries == table->allocated_size)
+ {
+ seek_error_type error = private_resize_table (table, table->num_entries * 2);
+ if (error != seek_no_error)
+ return private_show_error ("unable to resize seek table", error);
+ }
+
+ table->array[table->num_entries] = entry;
+ table->num_entries++;
+
+ return seek_no_error;
+}
+
+/*
+ * seek_get_nearest_entry
+ */
+
+seek_error_type seek_get_nearest_entry (seek_table_type *table, seek_entry_type *entry, int display_index, int offset)
+{
+ /* using offset>0 returns a modified seek_entry that sets the 'time-to-seek' to be $offset keyframes in the past.
+ */
+
+ if (NULL == table || NULL == table->array || table->num_entries <= 0) {
+ return private_show_error ("NULL or invalid seek table", seek_bad_argument);
+ }
+
+ if (NULL == entry) {
+ return private_show_error ("NULL entry buffer (for return)", seek_bad_argument);
+ }
+
+ if (display_index < table->array[0].display_index)
+ return private_show_error ("tried to seek to frame index before first frame", seek_bad_argument);
+
+ int i;
+ for (i=0; i < table->num_entries; i++)
+ if (table->array[i].display_index > display_index)
+ break;
+
+ i = i-1;
+
+ if (i<offset) /* target was lower than first element (including offset) */
+ return private_show_error ("target index out of table range (too small)", seek_bad_argument);
+
+ *entry = table->array[i];
+ (*entry).first_packet_dts = table->array[i-offset].first_packet_dts;
+
+ return seek_no_error;
+}
+
+
+/* read raw file */
+seek_table_type read_table_file(char *name)
+{
+ seek_table_type ans = { NULL, 0, 0 };
+
+ FILE *table_file = fopen(name, "r");
+ if (table_file == NULL)
+ return ans;
+
+ int completed_flag;
+ fscanf(table_file, "%d %d %d\n", &ans.num_frames, &ans.num_entries, &completed_flag);
+
+ if (completed_flag == 1)
+ ans.completed = seek_true;
+ else
+ ans.completed = seek_false;
+
+ ans.allocated_size = ans.num_entries;
+ ans.array = malloc (ans.allocated_size * sizeof(seek_entry_type));
+
+ int i;
+ for (i=0;i<ans.num_entries;i++)
+ fscanf(table_file, "%d %lld %lld\n", &(ans.array[i].display_index), &(ans.array[i].first_packet_dts), &(ans.array[i].last_packet_dts));
+
+ fclose(table_file);
+ return ans;
+}
+
+seek_error_type seek_show_raw_table (FILE* file, seek_table_type table)
+{
+ seek_entry_type *entry;
+ int index;
+
+ if (NULL == table.array || table.num_entries <= 0)
+ return private_show_error ("NULL or invalid seek table", seek_bad_argument);
+
+ int completed_flag = 0;
+ if (table.completed == seek_true)
+ completed_flag = 1;
+
+ fprintf(file, "%d %d %d\n", table.num_frames, table.num_entries, completed_flag);
+ for (index = 0; index < table.num_entries; index++)
+ {
+ entry = &(table.array[index]);
+
+ fprintf (file, "%d %lld %lld\n", entry->display_index, entry->first_packet_dts, entry->last_packet_dts);
+ }
+ return seek_no_error;
+}
+
+seek_error_type seek_show_table (seek_table_type table)
+{
+ seek_entry_type *entry;
+ int index;
+
+ if (NULL == table.array || table.num_entries <= 0) {
+ return private_show_error ("NULL or invalid seek table", seek_bad_argument);
+ }
+
+ int completed_flag = 0;
+ if (table.completed == seek_true)
+ completed_flag = 1;
+
+ fprintf (stderr, "--- Seek Table Dump ---\n");
+ fprintf (stderr, "n_frames: %d n_entries: %d completed: %d\n",table.num_frames, table.num_entries, completed_flag);
+ for (index = 0; index < table.num_entries; index++)
+ {
+ entry = &(table.array[index]);
+
+ fprintf (stderr, " %04d --> %08lld (%08lld)\n", entry->display_index, entry->first_packet_dts, entry->last_packet_dts);
+ }
+
+ fprintf (stderr, "-----------------------\n");
+
+ return seek_no_error;
+}
+
+/*
+ * private_show_error
+ */
+
+static seek_error_type private_show_error (const char *message, seek_error_type error)
+{
+ if (SHOW_ERROR_MESSAGES)
+ fprintf (stderr, " ===> seek_indices: %s\n", message);
+
+ return error;
+}
+
+/*
+ * private_resize_table
+ */
+
+static seek_error_type private_resize_table (seek_table_type *table, int new_size)
+{
+ seek_entry_type *new_array = NULL;
+
+ if (table == NULL || new_size < 0) {
+ return private_show_error ("invalid argument for private_resize_table()", seek_malloc_failed);
+ }
+
+ new_array = (seek_entry_type *)malloc (sizeof (seek_entry_type) * new_size);
+ if (NULL == new_array) {
+ return private_show_error ("unable to allocate more space for table", seek_malloc_failed);
+ }
+
+ memcpy (new_array, table->array, table->allocated_size * sizeof (seek_entry_type));
+ free (table->array);
+
+ table->allocated_size = new_size;
+ table->array = new_array;
+
+ return seek_no_error;
+}
diff --git a/ffmpeg-fas/seek_indices.h b/ffmpeg-fas/seek_indices.h
new file mode 100644
index 0000000..e908979
--- /dev/null
+++ b/ffmpeg-fas/seek_indices.h
@@ -0,0 +1,94 @@
+/*****************************************************************************
+ * Copyright 2008. Pittsburgh Pattern Recognition, Inc.
+ *
+ * This file is part of the Frame Accurate Seeking extension library to
+ * ffmpeg (ffmpeg-fas).
+ *
+ * ffmpeg-fas is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * The ffmpeg-fas library 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 Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the ffmpeg-fas library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ ******************************************************************************/
+
+#ifndef FAS_SEEK_INDICES_H
+#define FAS_SEEK_INDICES_H
+
+#include <stdint.h>
+#include <stdio.h>
+
+/* If C++ then we need to __extern "C". Compiler defines __cplusplus */
+#ifdef __cplusplus
+#define __extern extern "C"
+#else
+#define __extern extern
+#endif
+
+
+/**********************************************************************
+ * Seek Table Types
+ **********************************************************************/
+
+typedef enum
+{
+ seek_no_error,
+ seek_unknown_error,
+ seek_bad_argument,
+ seek_malloc_failed,
+} seek_error_type;
+
+typedef enum
+{
+ seek_false = 0,
+ seek_true = 1
+} seek_boolean_type;
+
+typedef struct
+{
+ int display_index;
+ int64_t first_packet_dts;
+ int64_t last_packet_dts;
+} seek_entry_type;
+
+typedef struct
+{
+ seek_entry_type *array;
+ seek_boolean_type completed;
+ int num_frames; // total number of frames
+ int num_entries; // ie, number of seek-points (keyframes)
+ int allocated_size;
+} seek_table_type;
+
+
+
+/**********************************************************************
+ * Seek Table Functions
+ **********************************************************************/
+
+
+__extern seek_table_type seek_init_table (int initial_size);
+__extern void seek_release_table (seek_table_type *table);
+
+__extern seek_table_type seek_copy_table (seek_table_type source);
+__extern int compare_seek_tables(seek_table_type t1, seek_table_type t2);
+
+__extern seek_error_type seek_append_table_entry (seek_table_type *table, seek_entry_type entry);
+
+__extern seek_error_type seek_get_nearest_entry (seek_table_type *table, seek_entry_type *entry, int display_index, int offset);
+
+__extern seek_error_type seek_show_table (seek_table_type table); /* human readable */
+__extern seek_error_type seek_show_raw_table (FILE *file, seek_table_type table);
+
+__extern seek_table_type read_table_file(char *name); /* read raw file */
+
+#endif
+
+/**** End of File *****************************************************/
diff --git a/ffmpeg-fas/test/build.sh b/ffmpeg-fas/test/build.sh
new file mode 100755
index 0000000..d00dd63
--- /dev/null
+++ b/ffmpeg-fas/test/build.sh
@@ -0,0 +1,7 @@
+LINK="../lib/libffmpeg_fas.so -lm -lz "
+gcc dump_frames.c -I.. $LINK -o dump_frames
+gcc dump_keyframes.c -I.. $LINK -o dump_keyframes
+gcc show_seek_table.c -I.. $LINK -o show_seek_table
+gcc seek_test.c -I.. $LINK -o seek_test
+gcc external_seek_test.c -I.. $LINK -o external_seek_test
+gcc generate_seek_table.c -I.. -I../ffmpeg/ ../ffmpeg/libavformat/libavformat.a ../ffmpeg/libavutil/libavutil.a ../ffmpeg/libavcodec/libavcodec.a -lm -lz ../lib/libffmpeg_fas.so -o generate_seek_table \ No newline at end of file
diff --git a/ffmpeg-fas/test/dump_frames.c b/ffmpeg-fas/test/dump_frames.c
new file mode 100644
index 0000000..6b4ccb7
--- /dev/null
+++ b/ffmpeg-fas/test/dump_frames.c
@@ -0,0 +1,67 @@
+/*****************************************************************************
+ * Copyright 2008. Pittsburgh Pattern Recognition, Inc.
+ *
+ * This file is part of the Frame Accurate Seeking extension library to
+ * ffmpeg (ffmpeg-fas).
+ *
+ * ffmpeg-fas is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * The ffmpeg-fas library 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 Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the ffmpeg-fas library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ ******************************************************************************/
+
+#include "ffmpeg_fas.h"
+#include "test_support.h"
+#include <stdio.h>
+
+int main (int argc, char **argv)
+{
+ char filename_buffer [255];
+
+ fas_error_type video_error;
+ fas_context_ref_type context;
+ fas_raw_image_type image_buffer;
+
+ if (argc < 2) {
+ fprintf (stderr, "usage: %s <video_file>\n", argv[0]);
+ return -1;
+ }
+
+ fas_initialize (FAS_FALSE);
+
+ fprintf(stderr, "%s : ",argv[1]);
+ video_error = fas_open_video (&context, argv[1]);
+ if (video_error != FAS_SUCCESS)
+ fail("failed to open\n");
+
+ int counter = 0;
+ while (fas_frame_available (context))
+ {
+
+ if (FAS_SUCCESS != fas_get_frame (context, &image_buffer))
+ fail("failed on rgb image\n");
+
+ char filename[50];
+ sprintf(filename, "frame_%04d.ppm", counter);
+
+ fprintf(stderr, "Writing %s (counter=%d frame_index=%d)\n", filename, counter, fas_get_frame_index(context));
+ ppm_save(&image_buffer, filename);
+
+ fas_free_frame (image_buffer);
+
+ video_error = fas_step_forward (context);
+ counter++;
+ }
+
+ success();
+
+}
diff --git a/ffmpeg-fas/test/dump_keyframes.c b/ffmpeg-fas/test/dump_keyframes.c
new file mode 100644
index 0000000..4e1333e
--- /dev/null
+++ b/ffmpeg-fas/test/dump_keyframes.c
@@ -0,0 +1,76 @@
+/*****************************************************************************
+ * Copyright 2008. Pittsburgh Pattern Recognition, Inc.
+ *
+ * This file is part of the Frame Accurate Seeking extension library to
+ * ffmpeg (ffmpeg-fas).
+ *
+ * ffmpeg-fas is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * The ffmpeg-fas library 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 Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the ffmpeg-fas library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ ******************************************************************************/
+
+#include "ffmpeg_fas.h"
+#include "seek_indices.h"
+#include "test_support.h"
+#include <stdio.h>
+
+int main (int argc, char **argv)
+{
+ fas_error_type video_error;
+ fas_context_ref_type context, seek_context;
+
+ if (argc < 3) {
+ fprintf (stderr, "usage: %s <video_file> <seek_table>\n", argv[0]);
+ fail("arguments\n");
+ }
+
+ seek_table_type table = read_table_file(argv[2]);
+ if (table.num_entries == 0)
+ fail("bad table\n");
+
+ fas_initialize (FAS_TRUE);
+
+ video_error = fas_open_video (&context, argv[1]);
+ if (video_error != FAS_SUCCESS) fail("fail on open\n");
+
+ video_error = fas_put_seek_table(context, table);
+ if (video_error != FAS_SUCCESS) fail("fail on put_seek_table\n");
+
+ video_error = fas_open_video (&seek_context, argv[1]);
+ if (video_error != FAS_SUCCESS) fail("fail on open\n");
+
+ int i;
+ for(i=0;i<table.num_entries;i++)
+ {
+ // int frame_index = table.array[table.num_entries - i - 1].display_index;
+ int frame_index = table.array[i].display_index;
+ if (FAS_SUCCESS != fas_seek_to_frame(context, frame_index))
+ fail("failed on seek");
+
+ fas_raw_image_type image_buffer;
+
+ if (FAS_SUCCESS != fas_get_frame (context, &image_buffer))
+ fail("failed on rgb image\n");
+
+ char filename[50];
+ sprintf(filename, "frame_%04d.ppm", frame_index);
+
+ fprintf(stderr, "Writing %s (seek_table_value=%d frame_index=%d)\n", filename, frame_index, fas_get_frame_index(context));
+ ppm_save(&image_buffer, filename);
+
+ fas_free_frame (image_buffer);
+ }
+
+ success();
+}
+
diff --git a/ffmpeg-fas/test/external_seek_test.c b/ffmpeg-fas/test/external_seek_test.c
new file mode 100644
index 0000000..d81c141
--- /dev/null
+++ b/ffmpeg-fas/test/external_seek_test.c
@@ -0,0 +1,172 @@
+/*****************************************************************************
+ * Copyright 2008. Pittsburgh Pattern Recognition, Inc.
+ *
+ * This file is part of the Frame Accurate Seeking extension library to
+ * ffmpeg (ffmpeg-fas).
+ *
+ * ffmpeg-fas is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * The ffmpeg-fas library 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 Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the ffmpeg-fas library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ ******************************************************************************/
+
+/* test seek using external table */
+
+#include "ffmpeg_fas.h"
+#include "seek_indices.h"
+#include "test_support.h"
+#include <stdio.h>
+
+#define TEST_SET_SIZE 1000
+#define N_ITERATIONS 500
+
+int compare_frames(fas_raw_image_type img1, fas_raw_image_type img2)
+{
+ // printf("(%d %d) (%d %d) (%d %d) (%d %d)\n", img1.width, img2.width,
+ // img1.height, img2.height,
+ // img1.bytes_per_line, img2.bytes_per_line,
+ // img1.color_space, img2.color_space);
+
+ if ((img1.width != img2.width) ||
+ (img1.height != img2.height) ||
+ (img1.bytes_per_line != img2.bytes_per_line) ||
+ (img1.color_space != img2.color_space))
+ return 0;
+
+ int i,j;
+ int mask = 0;
+
+ for (i=0;i<img1.height;i++)
+ for(j=0;j<img1.bytes_per_line;j++)
+ {
+ //printf("%d ", (img1.data[i*img1.bytes_per_line+j] - img2.data[i*img1.bytes_per_line+j+j]));
+ mask |= (img1.data[i*img1.bytes_per_line+j] - img2.data[i*img1.bytes_per_line+j]);
+ }
+
+ if (mask == 0)
+ return 1;
+ else
+ return 0;
+}
+
+void do_random_test(fas_context_ref_type context, int start, int stop, int count)
+{
+ // printf ("start: %d stop: %d\n", start, stop );
+
+ while (fas_get_frame_index(context) < start)
+ if (FAS_SUCCESS != fas_step_forward(context))
+ fail("failed on advancement\n");
+
+ fas_raw_image_type *ref_frames = malloc( (stop - start + 1)* sizeof(fas_raw_image_type));
+
+ int i;
+ fas_error_type video_error;
+
+ while (fas_get_frame_index(context) <= stop)
+ {
+ i = fas_get_frame_index(context) - start;
+
+ video_error = fas_get_frame(context, &(ref_frames[i]));
+ if (video_error != FAS_SUCCESS) fail("fail on test(1)\n");
+
+ video_error = fas_step_forward(context);
+ if (video_error != FAS_SUCCESS) fail("fail on test(2)\n");
+
+ }
+
+ int index = -1;
+ int prev_index;
+
+ for (i=0;i<count;i++)
+ {
+ int offset = random() % (stop - start + 1);
+ prev_index = index;
+ index = start + offset;
+
+ video_error = fas_seek_to_frame(context, index);
+ if (video_error != FAS_SUCCESS) fail("fail on test(seek)\n");
+
+
+ fas_raw_image_type test_frame;
+ video_error = fas_get_frame(context, &test_frame);
+ if (video_error != FAS_SUCCESS) fail("fail on test(seek2)\n");
+
+ // printf("offset: %d / %d\n", offset, stop - start + 1);
+
+ if (!compare_frames(test_frame, ref_frames[offset]))
+ {
+ char buffer[70];
+
+ sprintf(buffer, "fail-%d-test.ppm", index);
+ ppm_save(&test_frame, buffer);
+ sprintf(buffer, "fail-%d-ref.ppm", index);
+ ppm_save(&ref_frames[offset], buffer);
+ sprintf(buffer, "failed on compare after seeking (%d->%d)\n", prev_index, index);
+
+ fail(buffer);
+ }
+
+ fas_free_frame(test_frame);
+ }
+
+ for (i=0;i<stop - start + 1;i++)
+ free(ref_frames[i].data);
+
+ free(ref_frames);
+}
+
+int main (int argc, char **argv)
+{
+ fas_error_type video_error;
+ fas_context_ref_type context;
+
+ if (argc < 3) {
+ fprintf (stderr, "usage: %s <video_file> <seek_table>\n", argv[0]);
+ fail("arguments\n");
+ }
+
+ fprintf(stderr, "%s : ", argv[1]);
+
+ seek_table_type table = read_table_file(argv[2]);
+ if (table.num_entries == 0)
+ fail("bad table\n");
+
+ fas_initialize (FAS_FALSE);
+
+ video_error = fas_open_video (&context, argv[1]);
+ if (video_error != FAS_SUCCESS) fail("fail on open\n");
+
+ video_error = fas_put_seek_table(context, table);
+ if (video_error != FAS_SUCCESS) fail("fail on put_seek_table\n");
+
+ if (fas_get_frame_count(context) < 0)
+ fail("n_frames = -1\n");
+
+ if (fas_get_frame_count(context) < TEST_SET_SIZE)
+ do_random_test(context, 0, fas_get_frame_count(context) - 1, N_ITERATIONS);
+ else if (fas_get_frame_count(context) < TEST_SET_SIZE * 2)
+ {
+ do_random_test(context, 0, fas_get_frame_count(context) / 2 - 1, N_ITERATIONS / 2);
+ do_random_test(context, fas_get_frame_count(context) / 2 + 1, fas_get_frame_count(context) - 1 , N_ITERATIONS / 2);
+ }
+ else
+ {
+ do_random_test(context, 0, TEST_SET_SIZE, N_ITERATIONS / 2);
+ do_random_test(context, fas_get_frame_count(context) - TEST_SET_SIZE, fas_get_frame_count(context) - 1 , N_ITERATIONS / 2);
+ }
+
+ seek_release_table(&table);
+ fas_close_video(context);
+
+ success();
+}
+
diff --git a/ffmpeg-fas/test/generate_seek_table.c b/ffmpeg-fas/test/generate_seek_table.c
new file mode 100644
index 0000000..5549f57
--- /dev/null
+++ b/ffmpeg-fas/test/generate_seek_table.c
@@ -0,0 +1,209 @@
+/*****************************************************************************
+ * Copyright 2008. Pittsburgh Pattern Recognition, Inc.
+ *
+ * This file is part of the Frame Accurate Seeking extension library to
+ * ffmpeg (ffmpeg-fas).
+ *
+ * ffmpeg-fas is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * The ffmpeg-fas library 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 Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the ffmpeg-fas library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ ******************************************************************************/
+
+#include "libavcodec/avcodec.h"
+#include "libavformat/avformat.h"
+#include <stdio.h>
+#include <string.h>
+#include "seek_indices.h"
+
+/* This executable is used for creating experimental seek tables.
+ The show_seek_table executable will show the seek-table as ffmpeg_fas
+ currently creates them.
+ */
+
+int main (int argc, char **argv)
+{
+ av_log_level = AV_LOG_QUIET;
+
+ if (argc < 2) {
+ fprintf (stderr, "usage: %s <video_file>\n", argv[0]);
+ return -1;
+ }
+
+ av_register_all();
+
+ AVFormatContext *pFormatCtx;
+ if (av_open_input_file(&pFormatCtx, argv[1], NULL, 0, NULL) !=0)
+ return -1;
+
+ if (av_find_stream_info(pFormatCtx)<0)
+ return -1;
+
+ unsigned int stream_id = -1;
+ unsigned int i;
+
+ for (i = 0; i < pFormatCtx->nb_streams; i++)
+ if (pFormatCtx->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO)
+ {
+ stream_id = i;
+ break;
+ }
+
+ if (stream_id == -1)
+ return -1;
+
+ AVCodecContext *pCodecCtx = pFormatCtx->streams[stream_id]->codec;
+ AVCodec *pCodec;
+ pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
+ if (pCodec==NULL)
+ return -1;
+
+ if (avcodec_open(pCodecCtx, pCodec)<0)
+ return -1;
+
+
+ // printf("\n%s \n",argv[1]);
+
+ AVPacket Packet;
+ int count = 0;
+ int key_packets = 0;
+ int non_key_packets = 0;
+
+ int frame_count = 0;
+ int key_frames = 0;
+ int non_key_frames = 0;
+
+ AVFrame *pFrame;
+ pFrame=avcodec_alloc_frame();
+ int frameFinished;
+
+ seek_table_type table;
+ table = seek_init_table (16);
+ seek_entry_type entry;
+
+ int64_t key_packet_dts;
+ int64_t prev_packet_dts = AV_NOPTS_VALUE;
+ int64_t first_packet_dts; /* ensure first keyframe gets first packet */
+
+ int is_first_packet = 1;
+ int frames_have_label = 1;
+
+ // const char *format_name = pFormatCtx->iformat->name;
+ // const char *codec_name = pFormatCtx->streams[stream_id]->codec->codec->name;
+
+
+ /* these avi formats do not have labeled keyframes (the packets are labeled only and the packets and keyframe align 1-to-1 */
+ /* DISABLING THIS TYPE OF GENERATION (these videos will be unseekable) */
+ // fprintf(stderr, "format: (%s) codec: (%s)\n", format_name, codec_name);
+/*
+ * if (!strcmp(format_name, "avi"))
+ * if (!strcmp(codec_name, "aasc") ||
+ * !strcmp(codec_name, "camtasia") ||
+ * !strcmp(codec_name, "cinepak") ||
+ * !strcmp(codec_name, "cyuv") ||
+ * !strcmp(codec_name, "huffyuv") ||
+ * !strcmp(codec_name, "indeo2") ||
+ * !strcmp(codec_name, "indeo3") ||
+ * !strcmp(codec_name, "msrle") ||
+ * !strcmp(codec_name, "msvideo1") ||
+ * !strcmp(codec_name, "mszh") ||
+ * !strcmp(codec_name, "qpeg") ||
+ * !strcmp(codec_name, "truemotion1") ||
+ * !strcmp(codec_name, "ultimotion") ||
+ * !strcmp(codec_name, "vp3") ||
+ * !strcmp(codec_name, "zlib"))
+ * frames_have_label = 0;
+ */
+
+ while (av_read_frame(pFormatCtx, &Packet) >= 0)
+ {
+ if (Packet.stream_index == stream_id)
+ {
+ // fprintf(stderr, "Packet: (P%d: %lld %lld %d)\n", count, Packet.pts, Packet.dts, Packet.flags);
+ if ((Packet.flags & PKT_FLAG_KEY) || is_first_packet )
+ {
+ /* when keyframes overlap in the stream, that means multiple packets labeled 'keyframe' will arrive before
+ the keyframe itself. this results in wrong assignments all around, but only the first one needs to be right.
+ for all the rest, the seek-code will rewind to the previous keyframe to get them right.
+ */
+ if (is_first_packet)
+ {
+ first_packet_dts = Packet.dts;
+ is_first_packet = 0;
+ }
+
+ // fprintf(stderr, "Packet: (P%d: %lld %lld)\n", count, Packet.pts, Packet.dts);
+
+ /* first keyframe gets own dts, others get previous packet's dts.. this is workaround for some mpegs */
+ /* sometimes you need the previous packet from the supposed keyframe packet to get a frame back that is */
+ /* actually a keyframe */
+
+ if (prev_packet_dts == AV_NOPTS_VALUE)
+ key_packet_dts = Packet.dts;
+ else
+ key_packet_dts = prev_packet_dts;
+
+ if (Packet.flags & PKT_FLAG_KEY)
+ key_packets++;
+ else
+ non_key_packets++;
+ }
+ else
+ non_key_packets++;
+
+
+ avcodec_decode_video(pCodecCtx, pFrame, &frameFinished, Packet.data, Packet.size);
+
+ if (frameFinished)
+ {
+
+ // fprintf(stderr, "Frame : (P%d F%d: %lld %lld L:%d)\n", count, frame_count, Packet.pts, Packet.dts, pFrame->key_frame);
+ if ((pFrame->key_frame && frames_have_label) || ((Packet.flags & PKT_FLAG_KEY) && !frames_have_label))
+ {
+ key_frames++;
+
+ entry.display_index = frame_count;
+ entry.first_packet_dts = key_packet_dts;
+ entry.last_packet_dts = Packet.dts;
+
+ /* ensure first keyframe gets first packet dts */
+ if (frame_count == 0)
+ entry.first_packet_dts = first_packet_dts;
+
+ seek_append_table_entry(&table, entry);
+
+ // fprintf(stderr, "Frame : (P%d F%d: %lld %lld)\n", count, frame_count, Packet.pts, Packet.dts);
+ }
+ else
+ non_key_frames++;
+ frame_count++;
+ }
+
+ count++;
+ prev_packet_dts = Packet.dts;
+ }
+
+ av_free_packet(&Packet);
+ }
+
+ // printf("\n");
+
+ fprintf (stderr, "Packets: key: %d nonkey: %d total: %d\n", key_packets, non_key_packets, count);
+ fprintf (stderr, "Frames : key: %d nonkey: %d total: %d\n", key_frames, non_key_frames, frame_count);
+
+ table.completed = seek_true;
+ table.num_frames = frame_count;
+
+ seek_show_raw_table(stdout, table);
+
+ return 1;
+}
diff --git a/ffmpeg-fas/test/movie_info.c b/ffmpeg-fas/test/movie_info.c
new file mode 100644
index 0000000..f7bf40e
--- /dev/null
+++ b/ffmpeg-fas/test/movie_info.c
@@ -0,0 +1,81 @@
+/*****************************************************************************
+ * Copyright 2008. Pittsburgh Pattern Recognition, Inc.
+ *
+ * This file is part of the Frame Accurate Seeking extension library to
+ * ffmpeg (ffmpeg-fas).
+ *
+ * ffmpeg-fas is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * The ffmpeg-fas library 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 Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the ffmpeg-fas library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ ******************************************************************************/
+
+#include <libavcodec/avcodec.h>
+#include <libavformat/avformat.h>
+
+#include <stdio.h>
+
+int main(int argc, char *argv[]) {
+ AVFormatContext *pFormatCtx;
+ int i, videoStream;
+ AVCodecContext *pCodecCtx;
+ AVCodec *pCodec;
+ AVFrame *pFrame;
+ AVFrame *pFrameRGB;
+ AVPacket packet;
+ int frameFinished;
+ int numBytes;
+ uint8_t *buffer;
+
+ if(argc < 2) {
+ printf("Please provide a movie file\n");
+ return -1;
+ }
+ // Register all formats and codecs
+ av_register_all();
+
+ // Open video file
+ if(av_open_input_file(&pFormatCtx, argv[1], NULL, 0, NULL)!=0)
+ return -1; // Couldn't open file
+
+ // Retrieve stream information
+ if(av_find_stream_info(pFormatCtx)<0)
+ return -1; // Couldn't find stream information
+
+ // Dump information about file onto standard error
+ dump_format(pFormatCtx, 0, argv[1], 0);
+
+ // 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)
+ return -1; // Didn't find a video stream
+
+ // 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) {
+ fprintf(stderr, "Unsupported codec!\n");
+ return -1; // Codec not found
+ }
+ // Open codec
+ if(avcodec_open(pCodecCtx, pCodec)<0)
+ return -1; // Could not open codec
+
+ return 0;
+}
diff --git a/ffmpeg-fas/test/run_test.py b/ffmpeg-fas/test/run_test.py
new file mode 100755
index 0000000..38dbb21
--- /dev/null
+++ b/ffmpeg-fas/test/run_test.py
@@ -0,0 +1,56 @@
+#!/usr/bin/python
+
+import sys
+import os
+
+def readFilelist(filename):
+ try:
+ f = open(filename, 'r')
+ except:
+ return []
+ return [ele[:-1] for ele in f.readlines()]
+
+def create_filter_func(cmd, log_file):
+ if log_file == "":
+ return lambda filename : 0 == os.system(cmd + " " + filename)
+ else:
+ return lambda filename : 0 == os.system(cmd + " " + filename + " 2>> " + log_file)
+
+def write_filelist(files, filename):
+ f = open(filename, 'w')
+ for arg in files:
+ f.write(arg + '\n')
+ f.close()
+
+if __name__ == "__main__":
+ if len(sys.argv) < 3 or len(sys.argv) > 4:
+ print "Usage: " + sys.argv[0] + " <test_executable> <file_list>"
+ raise SystemExit
+
+
+ if not os.path.isfile(sys.argv[1]):
+ print sys.argv[1] + " not found"
+ raise SystemExit
+
+ cmd = sys.argv[1]
+ base_name = cmd.split('/')[-1]
+
+ success_file = base_name + ".pass"
+ fail_file = base_name + ".fail"
+
+ if len(sys.argv) == 4:
+ log_file = sys.argv[3]
+ if os.path.isfile(log_file):
+ os.system("rm " + log_file)
+ else:
+ log_file = ""
+
+ files = readFilelist(sys.argv[2])
+
+ filterfunc = create_filter_func(cmd, log_file)
+ successful = filter(filterfunc, files)
+ failed = list(set(files) - set(successful))
+
+ write_filelist(failed, fail_file)
+ write_filelist(successful, success_file)
+
diff --git a/ffmpeg-fas/test/seek_test.c b/ffmpeg-fas/test/seek_test.c
new file mode 100644
index 0000000..77f045e
--- /dev/null
+++ b/ffmpeg-fas/test/seek_test.c
@@ -0,0 +1,162 @@
+/*****************************************************************************
+ * Copyright 2008. Pittsburgh Pattern Recognition, Inc.
+ *
+ * This file is part of the Frame Accurate Seeking extension library to
+ * ffmpeg (ffmpeg-fas).
+ *
+ * ffmpeg-fas is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * The ffmpeg-fas library 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 Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the ffmpeg-fas library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ ******************************************************************************/
+
+#include "ffmpeg_fas.h"
+#include "seek_indices.h"
+#include "test_support.h"
+#include <stdio.h>
+
+#define TEST_SET_SIZE 1000
+#define N_ITERATIONS 500
+
+int compare_frames(fas_raw_image_type img1, fas_raw_image_type img2)
+{
+ // printf("(%d %d) (%d %d) (%d %d) (%d %d)\n", img1.width, img2.width,
+ // img1.height, img2.height,
+ // img1.bytes_per_line, img2.bytes_per_line,
+ // img1.color_space, img2.color_space);
+
+ if ((img1.width != img2.width) ||
+ (img1.height != img2.height) ||
+ (img1.bytes_per_line != img2.bytes_per_line) ||
+ (img1.color_space != img2.color_space))
+ return 0;
+
+ int i,j;
+ int mask = 0;
+
+ for (i=0;i<img1.height;i++)
+ for(j=0;j<img1.bytes_per_line;j++)
+ {
+ //printf("%d ", (img1.data[i*img1.bytes_per_line+j] - img2.data[i*img1.bytes_per_line+j+j]));
+ mask |= (img1.data[i*img1.bytes_per_line+j] - img2.data[i*img1.bytes_per_line+j]);
+ }
+
+ if (mask == 0)
+ return 1;
+ else
+ return 0;
+}
+
+void do_random_test(fas_context_ref_type context, int start, int stop, int count)
+{
+ // printf ("start: %d stop: %d\n", start, stop );
+
+ while (fas_get_frame_index(context) < start)
+ if (FAS_SUCCESS != fas_step_forward(context))
+ fail("failed on advancement\n");
+
+ fas_raw_image_type *ref_frames = malloc( (stop - start + 1)* sizeof(fas_raw_image_type));
+
+ int i;
+ fas_error_type video_error;
+
+ while (fas_get_frame_index(context) <= stop)
+ {
+ i = fas_get_frame_index(context) - start;
+
+ video_error = fas_get_frame(context, &(ref_frames[i]));
+ if (video_error != FAS_SUCCESS) fail("fail on test(1)\n");
+
+ video_error = fas_step_forward(context);
+ if (video_error != FAS_SUCCESS) fail("fail on test(2)\n");
+
+ }
+
+ int index = -1;
+ int prev_index;
+
+ for (i=0;i<count;i++)
+ {
+ int offset = random() % (stop - start + 1);
+ prev_index = index;
+ index = start + offset;
+
+ video_error = fas_seek_to_frame(context, index);
+ if (video_error != FAS_SUCCESS) fail("fail on test(seek)\n");
+
+
+ fas_raw_image_type test_frame;
+ video_error = fas_get_frame(context, &test_frame);
+ if (video_error != FAS_SUCCESS) fail("fail on test(seek2)\n");
+
+ // printf("offset: %d / %d\n", offset, stop - start + 1);
+
+ if (!compare_frames(test_frame, ref_frames[offset]))
+ {
+ char buffer[70];
+
+ sprintf(buffer, "fail-%d-test.ppm", index);
+ ppm_save(&test_frame, buffer);
+ sprintf(buffer, "fail-%d-ref.ppm", index);
+ ppm_save(&ref_frames[offset], buffer);
+ sprintf(buffer, "failed on compare after seeking (%d->%d)\n", prev_index, index);
+
+ fail(buffer);
+ }
+
+ fas_free_frame(test_frame);
+ }
+
+ for (i=0;i<stop - start + 1;i++)
+ free(ref_frames[i].data);
+
+ free(ref_frames);
+}
+
+int main (int argc, char **argv)
+{
+ fas_error_type video_error;
+ fas_context_ref_type context;
+
+ if (argc < 2) {
+ fprintf (stderr, "usage: %s <video_file>\n", argv[0]);
+ fail("arguments\n");
+ }
+
+ fprintf(stderr, "%s : ", argv[1]);
+
+ fas_initialize (FAS_FALSE);
+
+ video_error = fas_open_video (&context, argv[1]);
+ if (video_error != FAS_SUCCESS) fail("fail on open\n");
+
+ if (fas_get_frame_count(context) < 0)
+ fail("failed on counting frames (completing seek table... bad table?)\n");
+
+ if (fas_get_frame_count(context) < TEST_SET_SIZE)
+ do_random_test(context, 0, fas_get_frame_count(context) - 1, N_ITERATIONS);
+ else if (fas_get_frame_count(context) < TEST_SET_SIZE * 2)
+ {
+ do_random_test(context, 0, fas_get_frame_count(context) / 2 - 1, N_ITERATIONS / 2);
+ do_random_test(context, fas_get_frame_count(context) / 2 + 1, fas_get_frame_count(context) - 1 , N_ITERATIONS / 2);
+ }
+ else
+ {
+ do_random_test(context, 0, TEST_SET_SIZE, N_ITERATIONS / 2);
+ do_random_test(context, fas_get_frame_count(context) - TEST_SET_SIZE, fas_get_frame_count(context) - 1 , N_ITERATIONS / 2);
+ }
+
+ fas_close_video(context);
+
+ success();
+}
+
diff --git a/ffmpeg-fas/test/show_seek_table.c b/ffmpeg-fas/test/show_seek_table.c
new file mode 100644
index 0000000..6974bc2
--- /dev/null
+++ b/ffmpeg-fas/test/show_seek_table.c
@@ -0,0 +1,59 @@
+/*****************************************************************************
+ * Copyright 2008. Pittsburgh Pattern Recognition, Inc.
+ *
+ * This file is part of the Frame Accurate Seeking extension library to
+ * ffmpeg (ffmpeg-fas).
+ *
+ * ffmpeg-fas is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * The ffmpeg-fas library 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 Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the ffmpeg-fas library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ ******************************************************************************/
+
+#include "seek_indices.h"
+#include "ffmpeg_fas.h"
+#include <stdio.h>
+
+int main (int argc, char **argv)
+{
+ fas_error_type video_error;
+ fas_context_ref_type context;
+ fas_raw_image_type image_buffer;
+
+ if (argc < 2) {
+ fprintf (stderr, "usage: %s <video_file>\n", argv[0]);
+ return -1;
+ }
+
+ fas_initialize (FAS_FALSE);
+
+ video_error = fas_open_video (&context, argv[1]);
+ if (video_error != FAS_SUCCESS)
+ return -1;
+
+ while (fas_frame_available (context))
+ {
+ if (FAS_SUCCESS != fas_get_frame (context, &image_buffer))
+ return -1;
+ fas_free_frame (image_buffer);
+
+ video_error = fas_step_forward (context);
+ }
+
+ seek_table_type table;
+ table = fas_get_seek_table(context);
+
+ seek_show_raw_table(stdout, table);
+
+ return 1;
+}
+
diff --git a/ffmpeg-fas/test/test_support.h b/ffmpeg-fas/test/test_support.h
new file mode 100644
index 0000000..5b91a1a
--- /dev/null
+++ b/ffmpeg-fas/test/test_support.h
@@ -0,0 +1,67 @@
+/*****************************************************************************
+ * Copyright 2008. Pittsburgh Pattern Recognition, Inc.
+ *
+ * This file is part of the Frame Accurate Seeking extension library to
+ * ffmpeg (ffmpeg-fas).
+ *
+ * ffmpeg-fas is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * The ffmpeg-fas library 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 Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the ffmpeg-fas library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ ******************************************************************************/
+
+#ifndef FAS_TEST_SUPPORT
+#define FAS_TEST_SUPPORT
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define fail(x) { fprintf(stderr, "fail : "); fprintf(stderr, x); exit(EXIT_FAILURE); }
+#define success() { fprintf(stderr, "success\n"); exit(EXIT_SUCCESS); }
+
+/*
+ * static void pgm_save(ppt_raw_image_type *image, char *filename)
+ * {
+ * FILE *f;
+ * int i;
+ *
+ * f=fopen(filename,"w");
+ * fprintf(f,"P5\n%d\n%d\n%d\n", image->width, image->height, 255);
+ *
+ * for(i=0; i<image->height; i++) {
+ * fwrite(image->data + i * image->bytes_per_line, 1, image->width, f);
+ * }
+ *
+ * fclose(f);
+ * }
+ */
+
+static void ppm_save(fas_raw_image_type *image, char *filename)
+{
+ FILE *f;
+ int i;
+
+ if (image->color_space != FAS_RGB24) {
+ return;
+ }
+
+ f=fopen(filename,"wb");
+ fprintf(f,"P6\n%d %d\n%d\n", image->width, image->height, 255);
+
+ for(i=0; i<image->height; i++) {
+ fwrite(image->data + i * image->bytes_per_line, 1, image->width * 3, f);
+ }
+
+ fclose(f);
+}
+
+#endif