diff options
Diffstat (limited to 'ffmpeg-fas')
| -rw-r--r-- | ffmpeg-fas/.gitignore | 3 | ||||
| -rw-r--r-- | ffmpeg-fas/COPYING.GPL | 339 | ||||
| -rw-r--r-- | ffmpeg-fas/COPYING.LGPL | 504 | ||||
| -rw-r--r-- | ffmpeg-fas/README | 31 | ||||
| -rwxr-xr-x | ffmpeg-fas/build.sh | 9 | ||||
| -rw-r--r-- | ffmpeg-fas/ffmpeg_fas.c | 914 | ||||
| -rw-r--r-- | ffmpeg-fas/ffmpeg_fas.def | 14 | ||||
| -rw-r--r-- | ffmpeg-fas/ffmpeg_fas.h | 120 | ||||
| -rw-r--r-- | ffmpeg-fas/ffmpeg_fas.vcproj | 166 | ||||
| -rw-r--r-- | ffmpeg-fas/private_errors.h | 32 | ||||
| -rw-r--r-- | ffmpeg-fas/seek_indices.c | 319 | ||||
| -rw-r--r-- | ffmpeg-fas/seek_indices.h | 94 | ||||
| -rw-r--r-- | ffmpeg-fas/seek_indices.o | bin | 0 -> 6200 bytes | |||
| -rwxr-xr-x | ffmpeg-fas/test/build.sh | 7 | ||||
| -rw-r--r-- | ffmpeg-fas/test/dump_frames.c | 67 | ||||
| -rw-r--r-- | ffmpeg-fas/test/dump_keyframes.c | 76 | ||||
| -rw-r--r-- | ffmpeg-fas/test/external_seek_test.c | 172 | ||||
| -rw-r--r-- | ffmpeg-fas/test/generate_seek_table.c | 209 | ||||
| -rw-r--r-- | ffmpeg-fas/test/movie_info.c | 81 | ||||
| -rwxr-xr-x | ffmpeg-fas/test/run_test.py | 56 | ||||
| -rw-r--r-- | ffmpeg-fas/test/seek_test.c | 162 | ||||
| -rw-r--r-- | ffmpeg-fas/test/show_seek_table.c | 59 | ||||
| -rw-r--r-- | ffmpeg-fas/test/test_support.h | 67 |
23 files changed, 3501 insertions, 0 deletions
diff --git a/ffmpeg-fas/.gitignore b/ffmpeg-fas/.gitignore new file mode 100644 index 0000000..40ef421 --- /dev/null +++ b/ffmpeg-fas/.gitignore @@ -0,0 +1,3 @@ +\#* +*~ +.svn
\ No newline at end of file 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..892bce6 --- /dev/null +++ b/ffmpeg-fas/README @@ -0,0 +1,31 @@ +Released under Lesser GNU Public License (LGPL) + +This is an extension to the ffmpeg video decoding library meant to support +a variety of extra functionality in support of video processing applications. +The primary additional feature added is the ability to do frame-accurate seeking +(by frame number). This is accomplished in a codec/format independant manner +using seek tables. + +It has been built and tested under Linux and Windows. + +**NOTE [12/09]**: +This package hasn't been kept fully up-to-date with +ffmpeg's changing API. Some modification is necessary to remove calls to deprecated +ffmpeg functionality. Patches welcome. +***************** + +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 + +Getting up and running: +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) +and built (./configure ; make) from the base directory.
\ No newline at end of file diff --git a/ffmpeg-fas/build.sh b/ffmpeg-fas/build.sh new file mode 100755 index 0000000..0b567f5 --- /dev/null +++ b/ffmpeg-fas/build.sh @@ -0,0 +1,9 @@ +cd `dirname $0` +FFMPEG_BASEDIR=../ + +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..29ba119 --- /dev/null +++ b/ffmpeg-fas/ffmpeg_fas.c @@ -0,0 +1,914 @@ +/***************************************************************************** + * 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" + +#if defined( _WIN32 ) && defined( STATIC_DLL ) +extern "C" +{ +#include "libavformat/avformat.h" +#include "libavcodec/avcodec.h" +int img_convert(AVPicture *dst, int dst_pix_fmt, const AVPicture *src, int src_pix_fmt, int src_width, int src_height); +} +#else +#include "libavformat/avformat.h" +#include "libavcodec/avcodec.h" +#endif /* _WIN32 && STATIC_DLL */ + +#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 + +enum PixelFormat fmt; + +/**** 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; +#ifndef _WIN32 + av_log_level = AV_LOG_INFO; +#endif + } + else + { + SHOW_ERROR_MESSAGES = 0; + SHOW_WARNING_MESSAGES = 0; +#ifndef _WIN32 + av_log_level = AV_LOG_QUIET; +#endif + } +} + +/* Set the output image colorspace */ +void fas_set_format(fas_color_space_type format) +{ + switch (format) + { + case FAS_GRAY8: + fmt = PIX_FMT_GRAY8; + break; + case FAS_ARGB32: + fmt = PIX_FMT_RGB32_1; + break; + case FAS_ABGR32: + fmt = PIX_FMT_BGR32_1; + break; + case FAS_YUV420P: + fmt = PIX_FMT_YUV420P; + break; + case FAS_YUYV422: + fmt = PIX_FMT_YUYV422; + break; + case FAS_UYVY422: + fmt = PIX_FMT_UYVY422; + break; + case FAS_YUV422P: + fmt = PIX_FMT_YUV422P; + break; + case FAS_YUV444P: + fmt = PIX_FMT_YUV444P; + break; + case FAS_RGB24: + fmt = PIX_FMT_RGB24; + break; + case FAS_BGR24: + fmt = PIX_FMT_BGR24; + break; + default: + fmt = PIX_FMT_RGB24; + break; + } +} + + +void fas_initialize (fas_boolean_type logging, fas_color_space_type format) +{ + fas_set_logging(logging); + fas_set_format(format); + 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)); + + switch (fmt) + { + case PIX_FMT_RGB24: + image_ptr->bytes_per_line = context->codec_context->width * 3; + image_ptr->color_space = FAS_RGB24; + break; + case PIX_FMT_BGR24: + image_ptr->bytes_per_line = context->codec_context->width * 3; + image_ptr->color_space = FAS_BGR24; + break; + case PIX_FMT_ARGB: + image_ptr->bytes_per_line = context->codec_context->width * 4; + image_ptr->color_space = FAS_ARGB32; + break; + case PIX_FMT_ABGR: + image_ptr->bytes_per_line = context->codec_context->width * 4; + image_ptr->color_space = FAS_ABGR32; + break; + case PIX_FMT_YUV420P: + image_ptr->bytes_per_line = (context->codec_context->width * 3) >> 1; + image_ptr->color_space = FAS_YUV420P; + break; + case PIX_FMT_YUYV422: + image_ptr->bytes_per_line = context->codec_context->width * 2; + image_ptr->color_space = FAS_YUYV422; + break; + case PIX_FMT_UYVY422: + image_ptr->bytes_per_line = context->codec_context->width * 2; + image_ptr->color_space = FAS_UYVY422; + break; + case PIX_FMT_YUV422P: + image_ptr->bytes_per_line = context->codec_context->width * 2; + image_ptr->color_space = FAS_YUV422P; + break; + case PIX_FMT_YUV444P: + image_ptr->bytes_per_line = context->codec_context->width * 3; + image_ptr->color_space = FAS_YUV444P; + break; + } + + buffer_size = image_ptr->bytes_per_line * context->codec_context->height; + + 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->width = context->codec_context->width; + image_ptr->height = context->codec_context->height; + + + 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, image_ptr->bytes_per_line); + } + + 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(fmt, 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, fmt, + ctx->codec_context->width, ctx->codec_context->height); + } + + if (img_convert((AVPicture *) ctx->rgb_frame_buffer, fmt, (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; +} + +unsigned long long fas_get_frame_duration(fas_context_ref_type context) +{ + if (context->format_context->streams[context->stream_idx]->time_base.den != context->format_context->streams[context->stream_idx]->r_frame_rate.num + || context->format_context->streams[context->stream_idx]->time_base.num != context->format_context->streams[context->stream_idx]->r_frame_rate.den) + { + double frac = (double)(context->format_context->streams[context->stream_idx]->r_frame_rate.den) / (double)(context->format_context->streams[context->stream_idx]->r_frame_rate.num); + return (unsigned long long)(frac*10000000.); + } + else + { + return (unsigned long long)(((double)(context->format_context->streams[context->stream_idx]->time_base.num)) + /((double)(context->format_context->streams[context->stream_idx]->time_base.den))*10000000.); + } +} + +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.def b/ffmpeg-fas/ffmpeg_fas.def new file mode 100644 index 0000000..e53c570 --- /dev/null +++ b/ffmpeg-fas/ffmpeg_fas.def @@ -0,0 +1,14 @@ +LIBRARY ffmpeg_fas +EXPORTS + fas_initialize + fas_open_video + fas_close_video + fas_free_frame + fas_get_frame + fas_get_frame_index + fas_get_frame_duration + fas_step_forward + fas_seek_to_frame + fas_get_frame_count + fas_get_current_height + fas_get_current_width diff --git a/ffmpeg-fas/ffmpeg_fas.h b/ffmpeg-fas/ffmpeg_fas.h new file mode 100644 index 0000000..a0e621a --- /dev/null +++ b/ffmpeg-fas/ffmpeg_fas.h @@ -0,0 +1,120 @@ +/***************************************************************************** + * 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_BGR24 = 3, + FAS_ARGB32 = 4, + FAS_ABGR32 = 5, + FAS_YUV420P = 6, + FAS_YUYV422 = 7, + FAS_UYVY422 = 8, + FAS_YUV422P = 9, + FAS_YUV444P = 10, +} 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, fas_color_space_type format); +__extern void fas_set_format (fas_color_space_type format); + +__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); + +__extern unsigned long long fas_get_frame_duration(fas_context_ref_type context); + +#endif diff --git a/ffmpeg-fas/ffmpeg_fas.vcproj b/ffmpeg-fas/ffmpeg_fas.vcproj new file mode 100644 index 0000000..7d6c862 --- /dev/null +++ b/ffmpeg-fas/ffmpeg_fas.vcproj @@ -0,0 +1,166 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="7.10" + Name="ffmpeg_fas" + ProjectGUID="{B50057CF-F030-4857-A894-401F4A13C13A}" + RootNamespace="ffmpeg_fas" + Keyword="ManagedCProj"> + <Platforms> + <Platform + Name="Win32"/> + </Platforms> + <Configurations> + <Configuration + Name="Debug|Win32" + OutputDirectory="$(ConfigurationName)" + IntermediateDirectory="$(ConfigurationName)" + ConfigurationType="2" + CharacterSet="2" + ManagedExtensions="FALSE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="..\FFmpeg\include\ffmpeg" + PreprocessorDefinitions="WIN32;_DEBUG;__STDC_CONSTANT_MACROS;STATIC_DLL" + MinimalRebuild="FALSE" + BasicRuntimeChecks="0" + RuntimeLibrary="3" + WarningLevel="3" + DebugInformationFormat="3" + CompileAs="2"/> + <Tool + Name="VCCustomBuildTool"/> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="avcodec-52.lib avdevice-52.lib avformat-52.lib avutil-49.lib" + OutputFile="$(OutDir)\$(ProjectName).dll" + LinkIncremental="1" + AdditionalLibraryDirectories="..\FFmpeg\lib" + ModuleDefinitionFile="ffmpeg_fas.def" + GenerateDebugInformation="TRUE" + AssemblyDebug="1" + ImportLibrary="$(OutDir)/$(TargetName).lib"/> + <Tool + Name="VCMIDLTool"/> + <Tool + Name="VCPostBuildEventTool"/> + <Tool + Name="VCPreBuildEventTool"/> + <Tool + Name="VCPreLinkEventTool"/> + <Tool + Name="VCResourceCompilerTool"/> + <Tool + Name="VCWebServiceProxyGeneratorTool"/> + <Tool + Name="VCXMLDataGeneratorTool"/> + <Tool + Name="VCWebDeploymentTool"/> + <Tool + Name="VCManagedWrapperGeneratorTool"/> + <Tool + Name="VCAuxiliaryManagedWrapperGeneratorTool"/> + </Configuration> + <Configuration + Name="Release|Win32" + OutputDirectory="$(ConfigurationName)" + IntermediateDirectory="$(ConfigurationName)" + ConfigurationType="2" + CharacterSet="2" + ManagedExtensions="FALSE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="..\FFmpeg\include\ffmpeg" + PreprocessorDefinitions="WIN32;NDEBUG;__STDC_CONSTANT_MACROS;STATIC_DLL" + MinimalRebuild="FALSE" + RuntimeLibrary="2" + WarningLevel="3" + DebugInformationFormat="0" + CompileAs="2"/> + <Tool + Name="VCCustomBuildTool"/> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="avcodec-52.lib avdevice-52.lib avformat-52.lib avutil-49.lib" + AdditionalLibraryDirectories="..\FFmpeg\lib" + ModuleDefinitionFile="ffmpeg_fas.def"/> + <Tool + Name="VCMIDLTool"/> + <Tool + Name="VCPostBuildEventTool"/> + <Tool + Name="VCPreBuildEventTool"/> + <Tool + Name="VCPreLinkEventTool"/> + <Tool + Name="VCResourceCompilerTool"/> + <Tool + Name="VCWebServiceProxyGeneratorTool"/> + <Tool + Name="VCXMLDataGeneratorTool"/> + <Tool + Name="VCWebDeploymentTool"/> + <Tool + Name="VCManagedWrapperGeneratorTool"/> + <Tool + Name="VCAuxiliaryManagedWrapperGeneratorTool"/> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <Filter + Name="Source Files" + Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx" + UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"> + <File + RelativePath=".\ffmpeg_fas.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + CompileAs="2"/> + </FileConfiguration> + </File> + <File + RelativePath=".\seek_indices.c"> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + CompileAs="2"/> + </FileConfiguration> + </File> + </Filter> + <Filter + Name="Header Files" + Filter="h;hpp;hxx;hm;inl;inc;xsd" + UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"> + <File + RelativePath=".\ffmpeg_fas.h"> + </File> + <File + RelativePath=".\private_errors.h"> + </File> + <File + RelativePath=".\seek_indices.h"> + </File> + </Filter> + <Filter + Name="Resource Files" + Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx" + UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"> + </Filter> + <Filter + Name="def" + Filter=""> + <File + RelativePath=".\ffmpeg_fas.def"> + </File> + </Filter> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/ffmpeg-fas/private_errors.h b/ffmpeg-fas/private_errors.h new file mode 100644 index 0000000..9369ae3 --- /dev/null +++ b/ffmpeg-fas/private_errors.h @@ -0,0 +1,32 @@ +/***************************************************************************** + * 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 + +#if defined( _WIN32 ) && defined( STATIC_DLL ) +static int SHOW_ERROR_MESSAGES; +static int SHOW_WARNING_MESSAGES; +#else +int SHOW_ERROR_MESSAGES; +int SHOW_WARNING_MESSAGES; +#endif /* _WIN32 && STATIC_DLL */ +#endif diff --git a/ffmpeg-fas/seek_indices.c b/ffmpeg-fas/seek_indices.c new file mode 100644 index 0000000..cb877c3 --- /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, (seek_boolean_type) 0, (seek_boolean_type) 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 = (seek_entry_type*) 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/seek_indices.o b/ffmpeg-fas/seek_indices.o Binary files differnew file mode 100644 index 0000000..da73b17 --- /dev/null +++ b/ffmpeg-fas/seek_indices.o 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..ee9406b --- /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, FAS_RGB24); + + 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..61eba5c --- /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, FAS_RGB24); + + 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..ee903ba --- /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, FAS_RGB24); + + 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..b145447 --- /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, FAS_RGB24); + + 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..f5dfd39 --- /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, FAS_RGB24); + + 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 |
